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

Stefano Sabatini stefano.sabatini-lala at poste.it
Wed Jul 27 11:56:32 CEST 2011


On date Wednesday 2011-07-27 01:05:17 +0300, Mina Nagy Zaki encoded:
> 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.

The list of the accepted parameters follows.

> +
> + 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"

Nit++: alphabetical order

> +#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);
> +    }

What about:
int av_asrc_buffer_add_audio_buffer_ref(AVFilterContext *abuffer_src,
                                        AVFilterBufferRef *samplesref, int flags);
?

consistent with vsrc_buffer.h, more API-robust.

> +
> +    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];

16 is not enough for the layout.

> +    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);
> +    }

docs mismatch

> +    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",

Maybe: sr -> rate or sample_rate for increased readability

> +           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");

This error needs to be handled.

> +    }
> +
> +    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 =
> +{

Nit: = { on the same line

> +    .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

Nit: we have vsrc_buffer.h, not sure if we should rather use
asrc_buffer.h for simmetry, not strong about this though.

> @@ -0,0 +1,79 @@
> +/*
> + * Copyright (c) 2010 by S.N. Hemanth Meenakshisundaram

I'd like to avoid explicit copyrights in public interface files (also
the interface was mostly designed by me).

> + *
> + * 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"

Nit++: external library deps comes first, so

#include "libavutil/fifo.h"
#include "avfilter.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;

This should be kept private.

> +
> +/**
> + * 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);

Ditto.

> +
> +/**
> + * 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);

Why was this needed?


More information about the ffmpeg-devel mailing list