[FFmpeg-devel] [PATCH 1/4] lavfi: add asrc_abuffer - audio source buffer filter

Mina Nagy Zaki mnzaki at gmail.com
Wed Jul 27 00:05:17 CEST 2011


From: S.N. Hemanth Meenakshisundaram <smeenaks at ucsd.edu>

With many modifications by Stefano.
---
 doc/filters.texi           |   50 ++++++++++
 libavfilter/Makefile       |    2 +
 libavfilter/allfilters.c   |    1 +
 libavfilter/asrc_abuffer.c |  225 ++++++++++++++++++++++++++++++++++++++++++++
 libavfilter/asrc_abuffer.h |   79 +++++++++++++++
 5 files changed, 357 insertions(+), 0 deletions(-)
 create mode 100644 libavfilter/asrc_abuffer.c
 create mode 100644 libavfilter/asrc_abuffer.h

diff --git a/doc/filters.texi b/doc/filters.texi
index 8054bff..92bde6e 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -1846,6 +1846,56 @@ Default value is 0.
 
 @c man end VIDEO FILTERS
 
+ at chapter Audio Sources
+ at c man begin AUDIO SOURCES
+
+Below is a description of the currently available audio sources.
+
+ at section abuffer
+
+Buffer audio frames, and make them available to the filter chain.
+
+This source is mainly intended for a programmatic use, in particular
+through the interface defined in @file{libavfilter/asrc_abuffer.h}.
+
+It accepts the following mandatory parameters:
+ at var{sample_fmt_string}:@var{channel_layout_string}
+
+Follows the list of the accepted parameters.
+
+ at table @option
+
+ at item sample_fmt_string
+
+A string representing the sample format of the buffered audio frames.
+It may be a number corresponding to a sample format, or a sample format
+name.
+
+ at item channel_layout_string
+
+A string representing the channel layout of the buffered audio frames.
+It may be a number corresponding to a channel layout, or a channel
+layout name.
+
+ at end table
+
+For example:
+ at example
+abuffer=s16:stereo
+ at end example
+
+will instruct the source to accept audio frames with format "s16" and
+stereo channel layout.
+Since the sample format with name "s16" corresponds to the number
+1 and the "stereo" channel layout corresponds to the value 3
+(check the enum SampleFormatInfo definition and the channel_layout_map
+structure, this example is equivalent to:
+ at example
+abuffer=1:3
+ at end example
+
+ at c man end AUDIO SOURCES
+
 @chapter Video Sources
 @c man begin VIDEO SOURCES
 
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 865ba1e..686fd30 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -65,6 +65,8 @@ OBJS-$(CONFIG_UNSHARP_FILTER)                += vf_unsharp.o
 OBJS-$(CONFIG_VFLIP_FILTER)                  += vf_vflip.o
 OBJS-$(CONFIG_YADIF_FILTER)                  += vf_yadif.o
 
+OBJS-$(CONFIG_ABUFFER_FILTER)                += asrc_abuffer.o
+
 OBJS-$(CONFIG_BUFFER_FILTER)                 += vsrc_buffer.o
 OBJS-$(CONFIG_COLOR_FILTER)                  += vsrc_color.o
 OBJS-$(CONFIG_FREI0R_SRC_FILTER)             += vf_frei0r.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 56baa50..49be7b7 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -37,6 +37,7 @@ void avfilter_register_all(void)
     REGISTER_FILTER (AFORMAT,     aformat,     af);
     REGISTER_FILTER (ANULL,       anull,       af);
 
+    REGISTER_FILTER (ABUFFER,     abuffer,     asrc);
     REGISTER_FILTER (ANULLSRC,    anullsrc,    asrc);
 
     REGISTER_FILTER (ANULLSINK,   anullsink,   asink);
diff --git a/libavfilter/asrc_abuffer.c b/libavfilter/asrc_abuffer.c
new file mode 100644
index 0000000..6341e36
--- /dev/null
+++ b/libavfilter/asrc_abuffer.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2010 S.N. Hemanth Meenakshisundaram
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Memory buffer source filter for audio
+ */
+
+#include "libavutil/eval.h"
+#include "libavutil/audioconvert.h"
+#include "asrc_abuffer.h"
+
+#define FIFO_SIZE 8
+
+static void buf_free(AVFilterBuffer *ptr)
+{
+    av_free(ptr);
+    return;
+}
+
+int av_asrc_buffer_add_samples(AVFilterContext *ctx,
+                               uint8_t *data[8], int linesize[8], int nb_samples,
+                               int sample_fmt, int64_t channel_layout, int planar,
+                               int64_t pts)
+{
+    ABufferSourceContext *abuffer = ctx->priv;
+    AVFilterBufferRef *samplesref;
+
+    if (av_fifo_space(abuffer->fifo) < sizeof(samplesref)) {
+        av_log(ctx, AV_LOG_ERROR,
+               "Buffering limit reached. Please consume some available frames "
+               "before adding new ones.\n");
+        return AVERROR(ENOMEM);
+    }
+
+    samplesref = avfilter_get_audio_buffer_ref_from_arrays(data, linesize, AV_PERM_WRITE,
+                                                           nb_samples, sample_fmt,
+                                                           channel_layout, planar);
+    if (!samplesref)
+        return AVERROR(ENOMEM);
+    samplesref->buf->free  = buf_free;
+    samplesref->pts = pts;
+
+    av_fifo_generic_write(abuffer->fifo, &samplesref, sizeof(samplesref), NULL);
+
+    return 0;
+}
+
+int av_asrc_buffer_add_buffer(AVFilterContext *ctx,
+                              uint8_t *buf, int buf_size,
+                              int sample_fmt, int64_t channel_layout,
+                              int64_t pts)
+{
+    /* compute pointers from buffer */
+    uint8_t *data[8];
+    int linesize[8];
+    int nb_channels = av_get_channel_layout_nb_channels(channel_layout),
+        sample_size = av_get_bytes_per_sample(sample_fmt),
+        nb_samples = buf_size / sample_size / nb_channels;
+
+    memset(data,     0, 8 * sizeof(data[0]));
+    memset(linesize, 0, 8 * sizeof(linesize[0]));
+
+    data[0] = buf;
+    linesize[0] = nb_samples * sample_size * nb_channels;
+
+    return av_asrc_buffer_add_samples(ctx,
+                                      data, linesize, nb_samples,
+                                      sample_fmt, channel_layout, 0, pts);
+}
+
+static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
+{
+    ABufferSourceContext *abuffer = ctx->priv;
+    char sample_fmt_str[8], chlayout_str[16], sample_rate_str[16];
+    int n = 0;
+    char *tail;
+    double sample_rate;
+
+    n = sscanf(args, "%7[^:]:%15[^:]:%15s",
+               sample_fmt_str, chlayout_str, sample_rate_str);
+    if (!args || n != 3) {
+        av_log(ctx, AV_LOG_ERROR,
+               "Expected 3 arguments, but only %d found in '%s'\n", n, args);
+        return AVERROR(EINVAL);
+    }
+
+    abuffer->sample_fmt = av_get_sample_fmt(sample_fmt_str);
+    if (abuffer->sample_fmt == AV_SAMPLE_FMT_NONE) {
+        char *tail;
+        abuffer->sample_fmt = strtol(sample_fmt_str, &tail, 0);
+        if (*tail || (unsigned)abuffer->sample_fmt >= AV_SAMPLE_FMT_NB) {
+            av_log(ctx, AV_LOG_ERROR, "Invalid sample format '%s'\n",
+                   sample_fmt_str);
+            return AVERROR(EINVAL);
+        }
+    }
+
+    abuffer->channel_layout = av_get_channel_layout(chlayout_str);
+    if (abuffer->channel_layout < AV_CH_LAYOUT_STEREO) {
+        char *tail;
+        abuffer->channel_layout = strtol(chlayout_str, &tail, 0);
+        if (*tail || abuffer->channel_layout < AV_CH_LAYOUT_STEREO) {
+            av_log(ctx, AV_LOG_ERROR, "Invalid channel layout '%s'\n",
+                   chlayout_str);
+            return AVERROR(EINVAL);
+        }
+    }
+
+    sample_rate = av_strtod(sample_rate_str, &tail);
+    if (*tail || sample_rate < 0 || (int)sample_rate != sample_rate) {
+        av_log(ctx, AV_LOG_ERROR, "Invalid value '%s' for rate",
+               sample_rate_str);
+        return AVERROR(EINVAL);
+    }
+    abuffer->sample_rate = sample_rate;
+
+    abuffer->fifo = av_fifo_alloc(FIFO_SIZE*sizeof(AVFilterBufferRef*));
+    if (!abuffer->fifo) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo, filter init failed.\n");
+        return AVERROR(ENOMEM);
+    }
+
+    av_get_channel_layout_string(chlayout_str, sizeof(chlayout_str),
+                                 -1, abuffer->channel_layout);
+    av_log(ctx, AV_LOG_INFO, "fmt:%s channel_layout:%s sr:%d\n",
+           av_get_sample_fmt_name(abuffer->sample_fmt), chlayout_str,
+           abuffer->sample_rate);
+
+    return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+    ABufferSourceContext *abuffer = ctx->priv;
+    av_fifo_free(abuffer->fifo);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+    ABufferSourceContext *abuffer = ctx->priv;
+    AVFilterFormats *formats;
+
+    formats = NULL;
+    avfilter_add_format(&formats, abuffer->sample_fmt);
+    avfilter_set_common_sample_formats(ctx, formats);
+
+    formats = NULL;
+    avfilter_add_format(&formats, abuffer->channel_layout);
+    avfilter_set_common_channel_layouts(ctx, formats);
+
+    formats = NULL;
+    avfilter_add_format(&formats, AVFILTER_PACKED); //FIXME: Assuming packed
+    avfilter_set_common_packing_formats(ctx, formats);
+
+    return 0;
+}
+
+static int config_props(AVFilterLink *inlink)
+{
+    ABufferSourceContext *abuffer = inlink->src->priv;
+    inlink->format         = abuffer->sample_fmt;
+    inlink->channel_layout = abuffer->channel_layout;
+    inlink->sample_rate    = abuffer->sample_rate;
+    return 0;
+}
+
+static int request_frame(AVFilterLink *inlink)
+{
+    ABufferSourceContext *abuffer = inlink->src->priv;
+    AVFilterBufferRef *samplesref;
+
+    if (!av_fifo_size(abuffer->fifo)) {
+        av_log(inlink->src, AV_LOG_ERROR,
+               "request_frame() called with no available frames!\n");
+    }
+
+    av_fifo_generic_read(abuffer->fifo, &samplesref, sizeof(samplesref), NULL);
+    avfilter_filter_samples(inlink, avfilter_ref_buffer(samplesref, ~0));
+    avfilter_unref_buffer(samplesref);
+
+    return 0;
+}
+
+static int poll_frame(AVFilterLink *link)
+{
+    ABufferSourceContext *abuffer = link->src->priv;
+    return av_fifo_size(abuffer->fifo)/sizeof(AVFilterBufferRef*);
+}
+
+AVFilter avfilter_asrc_abuffer =
+{
+    .name      = "abuffer",
+    .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them accessible to the filterchain."),
+    .priv_size = sizeof(ABufferSourceContext),
+    .query_formats = query_formats,
+
+    .init      = init,
+    .uninit    = uninit,
+
+    .inputs    = (AVFilterPad[]) {{ .name = NULL }},
+    .outputs   = (AVFilterPad[]) {{ .name            = "default",
+                                    .type            = AVMEDIA_TYPE_AUDIO,
+                                    .request_frame   = request_frame,
+                                    .poll_frame      = poll_frame,
+                                    .config_props    = config_props, },
+                                  { .name = NULL}},
+};
diff --git a/libavfilter/asrc_abuffer.h b/libavfilter/asrc_abuffer.h
new file mode 100644
index 0000000..de34a80
--- /dev/null
+++ b/libavfilter/asrc_abuffer.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2010 by S.N. Hemanth Meenakshisundaram
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFILTER_ASRC_ABUFFER_H
+#define AVFILTER_ASRC_ABUFFER_H
+
+#include "avfilter.h"
+#include "libavutil/fifo.h"
+
+/**
+ * @file
+ * memory buffer source filter for audio
+ */
+
+/**
+ * The Buffer Source Context
+ */
+typedef struct {
+    unsigned int sample_fmt;  ///< initial sample format indicated by client
+    int64_t channel_layout;   ///< initial channel layout indicated by client
+    int sample_rate;
+    AVFifoBuffer *fifo;       ///< FIFO buffer of audio frame pointers
+} ABufferSourceContext;
+
+/**
+ * Queue an audio buffer to the audio buffer source.
+ *
+ * @param abufsrc audio source buffer context
+ * @param data pointers to the samples planes
+ * @param linesize linesizes of each audio buffer plane
+ * @param nb_samples number of samples per channel
+ * @param sample_fmt sample format of the audio data
+ * @param ch_layout channel layout of the audio data
+ * @param planar flag to indicate if audio data is planar or packed
+ * @param pts presentation timestamp of the audio buffer
+ */
+int av_asrc_buffer_add_samples(AVFilterContext *abufsrc,
+                               uint8_t *data[8], int linesize[8],
+                               int nb_samples,
+                               int sample_fmt, int64_t ch_layout, int planar,
+                               int64_t pts);
+
+/**
+ * Queue an audio buffer to the audio buffer source.
+ *
+ * This is similar to av_asrc_buffer_add_samples(), but the samples
+ * are stored in a buffer with known size.
+ *
+ * @param abufsrc audio source buffer context
+ * @param buf pointer to the samples data, packed is assumed
+ * @param size the size in bytes of the buffer, it must contain an
+ * integer number of samples
+ * @param sample_fmt sample format of the audio data
+ * @param ch_layout channel layout of the audio data
+ * @param pts presentation timestamp of the audio buffer
+ */
+int av_asrc_buffer_add_buffer(AVFilterContext *abufsrc,
+                              uint8_t *buf, int buf_size,
+                              int sample_fmt, int64_t ch_layout,
+                              int64_t pts);
+
+#endif /* AVFILTER_ASRC_ABUFFER_H */
-- 
1.7.4.4



More information about the ffmpeg-devel mailing list