[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