[FFmpeg-devel] [PATCH 5/5] lavfi: reimplement MPlayer's af_pan filter for libavfilter.
Clément Bœsch
ubitux at gmail.com
Sun Nov 6 00:40:24 CET 2011
On Sat, Nov 05, 2011 at 09:21:51PM +0100, Nicolas George wrote:
> From: Clément Bœsch <ubitux at gmail.com>
>
>
> Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
> ---
> Changelog | 1 +
> doc/filters.texi | 36 +++++++++++
> libavfilter/Makefile | 1 +
> libavfilter/af_pan.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++
> libavfilter/allfilters.c | 1 +
> libavfilter/avfilter.h | 2 +-
> 6 files changed, 195 insertions(+), 1 deletions(-)
> create mode 100644 libavfilter/af_pan.c
>
>
> Note: I assumed that Clément would agree to relicense his work on af_pan
> under LGPL if Anders' copyright is not blocking.
>
Yes sure.
>
> diff --git a/Changelog b/Changelog
> index d28265d..988af13 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -76,6 +76,7 @@ easier to use. The changes are:
> - volume audio filter added
> - earwax audio filter added
> - libv4l2 support (--enable-libv4l2)
> +- pan audio filter added
>
>
> version 0.8:
> diff --git a/doc/filters.texi b/doc/filters.texi
> index 6c98dc0..1f9158c 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -183,6 +183,42 @@ The shown line contains a sequence of key/value pairs of the form
>
> A description of each shown parameter follows:
>
> + at section pan
> +
> +Mix channels with specific gain levels. The filter accepts the number of output
> +channels followed by a set of coefficients. The number of those gain levels
> +depends on the number of output channels of the given layout.
> +
> +The filter accepts parameters of the form:
> +"@var{l}:L0A:L0B:L0C:...L1A:L1B:L1C:...LnA:LnB:LnC:...]"
> +
> + at table @option
> + at item l
> +output channel layout or number of channels
> +
> + at item Lij
> +gain level (as a factor) of input channel i to mix in output channel j.
> + at end table
> +
> +Channel gain levels are grouped by input channel (you have @var{n} output
Since you changed the variable into 'l', you should update the 'n'
reference here.
[...]
> diff --git a/libavfilter/af_pan.c b/libavfilter/af_pan.c
> new file mode 100644
> index 0000000..69eb68e
> --- /dev/null
> +++ b/libavfilter/af_pan.c
> @@ -0,0 +1,155 @@
> +/*
> + * Copyright (C) 2002 Anders Johansson <ajh at atri.curtin.edu.au>
> + * Copyright (C) 2011 Clément Bœsch <ubitux at gmail.com>
> + *
You should add yourself here now :)
> + * 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 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
> + * Audio panning filter (channels mixing)
> + * Original code written by Anders Johansson for MPlayer,
> + * reimplemented for FFmpeg.
> + */
> +
> +#include <stdlib.h>
> +#include "libavcodec/avcodec.h"
> +#include "libavutil/avstring.h"
> +#include "libswresample/swresample.h" // only for SWR_CH_MAX
> +#include "avfilter.h"
> +#include "internal.h"
> +
> +typedef struct {
> + int nb_input_channels;
> + int nb_output_channels;
> + int64_t out_channels_layout;
> + int gain_level[SWR_CH_MAX][SWR_CH_MAX]; // +7.8 fixed point
I'm not familiar enough with fixed point arithmetic; what does the '+'
stand for?
> +} PanContext;
> +
> +static av_cold int init(AVFilterContext *ctx, const char *args0, void *opaque)
> +{
> + int i, j;
> + PanContext * const pan = ctx->priv;
> + int out_ch_id = 0, in_ch_id = 0;
> + char *arg, *tokenizer, *args = av_strdup(args0);
> +
> + if (!args)
> + return AVERROR(ENOMEM);
> + arg = av_strtok(args, ":", &tokenizer);
> + pan->out_channels_layout = av_get_channel_layout(arg);
> + if (!pan->out_channels_layout) {
> + av_log(ctx, AV_LOG_ERROR, "unknown channel layout \"%s\"\n", arg);
> + return AVERROR(EINVAL);
> + }
> + pan->nb_output_channels = av_get_channel_layout_nb_channels(pan->out_channels_layout);
> +
> + while (in_ch_id < SWR_CH_MAX && (arg = av_strtok(NULL, ":", &tokenizer))) {
> + pan->gain_level[out_ch_id++][in_ch_id] = 256 * strtof(arg, NULL);
> + if (out_ch_id >= pan->nb_output_channels) {
> + out_ch_id = 0;
> + in_ch_id++;
> + }
> + }
> + if (args)
> + av_log(ctx, AV_LOG_WARNING, "max of %d channels reached, "
> + "ignoring end of buffer\n", SWR_CH_MAX);
> + pan->nb_input_channels = in_ch_id;
> +
> + // summary
> + for (j = 0; j < pan->nb_output_channels; j++) {
> + av_log(ctx, AV_LOG_INFO, "output channel %d:", j);
> + for (i = 0; i < in_ch_id; i++)
> + av_log(ctx, AV_LOG_INFO, " %.1f", pan->gain_level[j][i] / 128.0);
Shouldn't this be /256?
> + av_log(ctx, AV_LOG_INFO, "\n");
> + }
> +
> + av_free(args);
> + return 0;
> +}
> +
> +static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
> +{
> + PanContext * const pan = inlink->dst->priv;
> + int i, o, n = insamples->audio->nb_samples;
> +
> + /* input */
> + //int nb_input_channels = av_get_channel_layout_nb_channels(inlink->channel_layout);
Does it still work as expected when the number of specified input channels
doesn't match the actual number of input channels?
> + const int16_t *in = (int16_t*)insamples->data[0];
> + const int16_t *in_end = in + n * pan->nb_input_channels;
> +
> + /* output */
> + AVFilterLink * const outlink = inlink->dst->outputs[0];
> + //int nb_output_channels = av_get_channel_layout_nb_channels(pan->out_channels_layout);
Feel free to remove this chunk as well if it works.
> + AVFilterBufferRef *outsamples = avfilter_get_audio_buffer(outlink, AV_PERM_WRITE, n);
> + int16_t *out = (int16_t*)outsamples->data[0];
> +
> + for (; in < in_end; in += pan->nb_input_channels) {
> + for (o = 0; o < pan->nb_output_channels; o++) {
> + int v = 0;
> + for (i = 0; i < pan->nb_input_channels; i++)
> + v += pan->gain_level[o][i] * in[i];
> + *(out++) = v >> 8;
Pointless braces?
Anyway, thanks a lot for submitting quickly this patchset.
[...]
--
Clément B.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 490 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20111106/1a22f2c8/attachment.asc>
More information about the ffmpeg-devel
mailing list