[FFmpeg-devel] [PATCH] af_mix: mix two audio streams

Clément Bœsch ubitux at gmail.com
Wed Dec 14 08:17:25 CET 2011


On Tue, Dec 13, 2011 at 04:57:15PM +0100, Matthieu Bouron wrote:
> Hi there,
> 
> Here is a first attempt to write an audio filter which merge two audio streams.
> Usage is:
> ffplay -f lavfi "amovie=test1.mp3[a];amovie=test2.mp3[b];[a][b]mix=0.7:0.3[out]"
> 
> The volume of each streams can be configured and default to 0.5:0.5 is
> not specified. It only support two s16 audio streams with same sample
> rate.
> Feel free to comment.
> 
> Matthieu

> From 78537e1c874d62b42b58de8da210dde28eb17859 Mon Sep 17 00:00:00 2001
> From: Matthieu Bouron <matthieu.bouron at gmail.com>
> Date: Sat, 10 Dec 2011 12:31:32 +0100
> Subject: [PATCH] af_mix: mix two audio streams.
> 
> ---
>  libavfilter/Makefile     |    1 +
>  libavfilter/af_mix.c     |  223 ++++++++++++++++++++++++++++++++++++++++++++++
>  libavfilter/allfilters.c |    1 +
>  3 files changed, 225 insertions(+), 0 deletions(-)
>  create mode 100644 libavfilter/af_mix.c
> 

You will need to bump lavfi minor version, and ideally add a Changelog
entry and document it in doc/filters.texi.

[...]
> +static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
> +{
> +    int i, n;
> +    double vol1, vol2;
> +    MixContext *mix = ctx->priv;
> +
> +    if (args) {
> +        n = sscanf(args, "%lf:%lf", &vol1, &vol2);
> +        switch (n) {
> +            case 0:
> +                mix->vol[0] = 0.5;
> +                mix->vol[1] = 0.5;
> +                break;
> +            case 1:
> +                mix->vol[0] = vol1;
> +                mix->vol[1] = 0.5;
> +                break;
> +            case 2:
> +                mix->vol[0] = vol1;
> +                mix->vol[1] = vol2;
> +                break;
> +            default:
> +                av_log(ctx, AV_LOG_ERROR, "sscanf error");
> +                return 1;

nit: you should remove one level of indent in the switch. Also, the error
isn't very explicit...

> +        }
> +        for (i = 0; i < 2; i++) {
> +            mix->vol_i[i] = (int)(mix->vol[i] * 256 + 0.5);
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +static int query_formats(AVFilterContext *ctx)
> +{
> +    int i;
> +    MixContext *mix = ctx->priv;
> +    AVFilterFormats *formats = NULL;
> +    enum AVSampleFormat sample_fmts[] = {
> +        AV_SAMPLE_FMT_S16,
> +        AV_SAMPLE_FMT_NONE
> +    };
> +    int packing_fmts[] = { AVFILTER_PACKED, -1 };

sample_fmts and packing_fmts could be const.

> +    int layout_fmts[] = {0, -1};
> +
[...]
> +    if (insamples->format == AV_SAMPLE_FMT_S16) {
> +        int16_t *in1 = NULL;
> +        int16_t *in2 = NULL;
> +        int16_t *out = NULL;
> +
> +        if (!mix->ended[0])
> +            in1 = (int16_t*)mix->buf[0]->data[0];
> +        if (!mix->ended[1])
> +            in2 = (int16_t*)mix->buf[1]->data[0];
> +        out = (int16_t*)outsamples->data[0];
> +
> +        for (i = 0; i < nb_samples; i++) {
> +            int64_t v1 = 0;
> +            int64_t v2 = 0;
> +            if (!mix->ended[0])
> +                v1 = (((int64_t)*in1++ * mix->vol_i[0] + 128) >> 8);
> +            if (!mix->ended[1])
> +                v2 = (((int64_t)*in2++ * mix->vol_i[1] + 128) >> 8);
> +            *out++ = av_clip_int16((v1 + v2) / 2);

Since your volumes are by default 0.5, is the /2 really needed here?

> +        }
> +
> +        for (i = 0; i < 2; i++) {
> +            if (!mix->ended[i]) {
> +                mix->buf_pos[i] += nb_samples;
> +                if (mix->buf_pos[i] == nb_samples) {
> +                    avfilter_unref_buffer(mix->buf[i]);
> +                    mix->buf[i] = 0;
> +                }
> +            }
> +        }
> +    }
> +
> +    avfilter_filter_samples(outlink, outsamples);
> +}
> +
> +static int request_frame(AVFilterLink *outlink)
> +{
> +    AVFilterContext *ctx = outlink->src;
> +    MixContext *mix = ctx->priv;
> +    int i;
> +
> +    for (i = 0; i < 2; i++)
> +        if (avfilter_request_frame(ctx->inputs[i]) != 0) {
> +            mix->ended[i] = 1;
> +        }

nit: the for without { } looks weird here, but it's at your own
discretion.

> +    return 0;
> +}
> +
> +AVFilter avfilter_af_mix = {
> +    .name           = "mix",
> +    .description    = NULL_IF_CONFIG_SMALL("Mix two audio streams."),

Superfluous period

-- 
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/20111214/9fdf1f7e/attachment.asc>


More information about the ffmpeg-devel mailing list