Merge remote-tracking branch 'qatar/master'
authorMichael Niedermayer <michaelni@gmx.at>
Mon, 9 Jul 2012 20:10:38 +0000 (22:10 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Mon, 9 Jul 2012 20:40:12 +0000 (22:40 +0200)
* qatar/master:
  mss3: use standard zigzag table
  mss3: split DSP functions that are used in MTS2(MSS4) into separate file
  motion-test: do not use getopt()
  tcp: add initial timeout limit for incoming connections
  configure: Change the rdtsc check to a linker check
  avconv: propagate fatal errors from lavfi.
  lavfi: add error handling to filter_samples().
  fate-run: make avconv() properly deal with multiple inputs.
  asplit: don't leak the input buffer.
  af_resample: fix request_frame() behavior.
  af_asyncts: fix request_frame() behavior.
  libx264: support aspect ratio switching
  matroskadec: honor error_recognition when encountering unknown elements.
  lavr: resampling: add support for s32p, fltp, and dblp internal sample formats
  lavr: resampling: add filter type and Kaiser window beta to AVOptions
  lavr: Use AV_SAMPLE_FMT_NONE to auto-select the internal sample format
  lavr: mix: validate internal sample format in ff_audio_mix_init()

Conflicts:
ffmpeg.c
ffplay.c
libavcodec/libx264.c
libavfilter/audio.c
libavfilter/split.c
libavformat/tcp.c
tests/fate-run.sh

Merged-by: Michael Niedermayer <michaelni@gmx.at>
38 files changed:
1  2 
libavcodec/Makefile
libavcodec/libx264.c
libavcodec/motion-test.c
libavcodec/mss3.c
libavcodec/mss34dsp.c
libavcodec/mss34dsp.h
libavfilter/af_aconvert.c
libavfilter/af_amerge.c
libavfilter/af_amix.c
libavfilter/af_aresample.c
libavfilter/af_asetnsamples.c
libavfilter/af_ashowinfo.c
libavfilter/af_astreamsync.c
libavfilter/af_asyncts.c
libavfilter/af_atempo.c
libavfilter/af_channelmap.c
libavfilter/af_channelsplit.c
libavfilter/af_earwax.c
libavfilter/af_pan.c
libavfilter/af_silencedetect.c
libavfilter/af_volume.c
libavfilter/asink_anullsink.c
libavfilter/audio.c
libavfilter/audio.h
libavfilter/avf_showwaves.c
libavfilter/avfilter.h
libavfilter/buffersink.c
libavfilter/buffersrc.c
libavfilter/f_settb.c
libavfilter/fifo.c
libavfilter/internal.h
libavfilter/sink_buffer.c
libavfilter/split.c
libavformat/matroskadec.c
libavformat/tcp.c
libavresample/resample_template.c
libavresample/utils.c
tests/fate-run.sh

@@@ -327,10 -292,9 +327,10 @@@ OBJS-$(CONFIG_MSMPEG4V3_ENCODER)       
                                            h263dec.o h263.o ituh263dec.o        \
                                            mpeg4videodec.o
  OBJS-$(CONFIG_MSRLE_DECODER)           += msrle.o msrledec.o
- OBJS-$(CONFIG_MSA1_DECODER)            += mss3.o
+ OBJS-$(CONFIG_MSA1_DECODER)            += mss3.o mss34dsp.o
  OBJS-$(CONFIG_MSS1_DECODER)            += mss1.o
  OBJS-$(CONFIG_MSVIDEO1_DECODER)        += msvideo1.o
 +OBJS-$(CONFIG_MSVIDEO1_ENCODER)        += msvideo1enc.o elbg.o
  OBJS-$(CONFIG_MSZH_DECODER)            += lcldec.o
  OBJS-$(CONFIG_MXPEG_DECODER)           += mxpegdec.o mjpegdec.o mjpeg.o
  OBJS-$(CONFIG_NELLYMOSER_DECODER)      += nellymoserdec.o nellymoser.o
Simple merge
@@@ -119,18 -119,12 +119,12 @@@ int main(int argc, char **argv
      int flags[2] = { AV_CPU_FLAG_MMX, AV_CPU_FLAG_MMX2 };
      int flags_size = HAVE_MMX2 ? 2 : 1;
  
-     for(;;) {
-         c = getopt(argc, argv, "h");
-         if (c == -1)
-             break;
-         switch(c) {
-         case 'h':
-             help();
-             return 1;
-         }
+     if (argc > 1) {
+         help();
+         return 1;
      }
  
 -    printf("Libav motion test\n");
 +    printf("ffmpeg motion test\n");
  
      ctx = avcodec_alloc_context3(NULL);
      ctx->dsp_mask = AV_CPU_FLAG_FORCE;
Simple merge
index 0000000,11abb2d..e4d4299
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,114 +1,114 @@@
 - * This file is part of Libav.
+ /*
+  * Common stuff for some Microsoft Screen codecs
+  * Copyright (C) 2012 Konstantin Shishkov
+  *
 - * Libav is free software; you can redistribute it and/or
++ * This file is part of FFmpeg.
+  *
 - * Libav is distributed in the hope that it will be useful,
++ * 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.
+  *
 - * License along with Libav; if not, write to the Free Software
++ * 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
+  */
+ #include <stdint.h>
+ #include "libavutil/common.h"
+ #include "mss34dsp.h"
+ static const uint8_t luma_quant[64] = {
+     16,  11,  10,  16,  24,  40,  51,  61,
+     12,  12,  14,  19,  26,  58,  60,  55,
+     14,  13,  16,  24,  40,  57,  69,  56,
+     14,  17,  22,  29,  51,  87,  80,  62,
+     18,  22,  37,  56,  68, 109, 103,  77,
+     24,  35,  55,  64,  81, 104, 113,  92,
+     49,  64,  78,  87, 103, 121, 120, 101,
+     72,  92,  95,  98, 112, 100, 103,  99
+ };
+ static const uint8_t chroma_quant[64] = {
+     17, 18, 24, 47, 99, 99, 99, 99,
+     18, 21, 26, 66, 99, 99, 99, 99,
+     24, 26, 56, 99, 99, 99, 99, 99,
+     47, 66, 99, 99, 99, 99, 99, 99,
+     99, 99, 99, 99, 99, 99, 99, 99,
+     99, 99, 99, 99, 99, 99, 99, 99,
+     99, 99, 99, 99, 99, 99, 99, 99,
+     99, 99, 99, 99, 99, 99, 99, 99
+ };
+ void ff_mss34_gen_quant_mat(uint16_t *qmat, int quality, int luma)
+ {
+     int i;
+     const uint8_t *qsrc = luma ? luma_quant : chroma_quant;
+     if (quality >= 50) {
+         int scale = 200 - 2 * quality;
+         for (i = 0; i < 64; i++)
+             qmat[i] = (qsrc[i] * scale + 50) / 100;
+     } else {
+         for (i = 0; i < 64; i++)
+             qmat[i] = (5000 * qsrc[i] / quality + 50) / 100;
+     }
+ }
+ #define DCT_TEMPLATE(blk, step, SOP, shift)                         \
+     const int t0 = -39409 * blk[7 * step] -  58980 * blk[1 * step]; \
+     const int t1 =  39410 * blk[1 * step] -  58980 * blk[7 * step]; \
+     const int t2 = -33410 * blk[5 * step] - 167963 * blk[3 * step]; \
+     const int t3 =  33410 * blk[3 * step] - 167963 * blk[5 * step]; \
+     const int t4 =          blk[3 * step] +          blk[7 * step]; \
+     const int t5 =          blk[1 * step] +          blk[5 * step]; \
+     const int t6 =  77062 * t4            +  51491 * t5;            \
+     const int t7 =  77062 * t5            -  51491 * t4;            \
+     const int t8 =  35470 * blk[2 * step] -  85623 * blk[6 * step]; \
+     const int t9 =  35470 * blk[6 * step] +  85623 * blk[2 * step]; \
+     const int tA = SOP(blk[0 * step] - blk[4 * step]);              \
+     const int tB = SOP(blk[0 * step] + blk[4 * step]);              \
+                                                                     \
+     blk[0 * step] = (  t1 + t6  + t9 + tB) >> shift;                \
+     blk[1 * step] = (  t3 + t7  + t8 + tA) >> shift;                \
+     blk[2 * step] = (  t2 + t6  - t8 + tA) >> shift;                \
+     blk[3 * step] = (  t0 + t7  - t9 + tB) >> shift;                \
+     blk[4 * step] = (-(t0 + t7) - t9 + tB) >> shift;                \
+     blk[5 * step] = (-(t2 + t6) - t8 + tA) >> shift;                \
+     blk[6 * step] = (-(t3 + t7) + t8 + tA) >> shift;                \
+     blk[7 * step] = (-(t1 + t6) + t9 + tB) >> shift;                \
+ #define SOP_ROW(a) ((a) << 16) + 0x2000
+ #define SOP_COL(a) ((a + 32) << 16)
+ void ff_mss34_dct_put(uint8_t *dst, int stride, int *block)
+ {
+     int i, j;
+     int *ptr;
+     ptr = block;
+     for (i = 0; i < 8; i++) {
+         DCT_TEMPLATE(ptr, 1, SOP_ROW, 13);
+         ptr += 8;
+     }
+     ptr = block;
+     for (i = 0; i < 8; i++) {
+         DCT_TEMPLATE(ptr, 8, SOP_COL, 22);
+         ptr++;
+     }
+     ptr = block;
+     for (j = 0; j < 8; j++) {
+         for (i = 0; i < 8; i++)
+             dst[i] = av_clip_uint8(ptr[i] + 128);
+         dst += stride;
+         ptr += 8;
+     }
+ }
index 0000000,b2cc550..2f9827d
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,45 +1,45 @@@
 - * This file is part of Libav.
+ /*
+  * Common stuff for some Microsoft Screen codecs
+  * Copyright (C) 2012 Konstantin Shishkov
+  *
 - * Libav is free software; you can redistribute it and/or
++ * This file is part of FFmpeg.
+  *
 - * Libav is distributed in the hope that it will be useful,
++ * 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.
+  *
 - * License along with Libav; if not, write to the Free Software
++ * 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 AVCODEC_MSS34DSP_H
+ #define AVCODEC_MSS34DSP_H
+ #include <stdint.h>
+ /**
+  * Generate quantisation matrix for given quality.
+  *
+  * @param qmat    destination matrix
+  * @param quality quality setting (1-100)
+  * @param luma    generate quantisation matrix for luma or chroma
+  */
+ void ff_mss34_gen_quant_mat(uint16_t *qmat, int quality, int luma);
+ /**
+  * Transform and output DCT block.
+  *
+  * @param dst     output plane
+  * @param stride  output plane stride
+  * @param block   block to transform and output
+  */
+ void ff_mss34_dct_put(uint8_t *dst, int stride, int *block);
+ #endif /* AVCODEC_MSS34DSP_H */
index 51167f4,0000000..dc9cf45
mode 100644,000000..100644
--- /dev/null
@@@ -1,172 -1,0 +1,174 @@@
- static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref)
 +/*
 + * Copyright (c) 2010 S.N. Hemanth Meenakshisundaram <smeenaks@ucsd.edu>
 + * Copyright (c) 2011 Stefano Sabatini
 + * Copyright (c) 2011 Mina Nagy Zaki
 + *
 + * 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
 + * sample format and channel layout conversion audio filter
 + */
 +
 +#include "libavutil/audioconvert.h"
 +#include "libavutil/avstring.h"
 +#include "libswresample/swresample.h"
 +#include "avfilter.h"
 +#include "audio.h"
 +#include "internal.h"
 +
 +typedef struct {
 +    enum AVSampleFormat  out_sample_fmt;
 +    int64_t              out_chlayout;
 +    struct SwrContext *swr;
 +} AConvertContext;
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args0)
 +{
 +    AConvertContext *aconvert = ctx->priv;
 +    char *arg, *ptr = NULL;
 +    int ret = 0;
 +    char *args = av_strdup(args0);
 +
 +    aconvert->out_sample_fmt  = AV_SAMPLE_FMT_NONE;
 +    aconvert->out_chlayout    = 0;
 +
 +    if ((arg = av_strtok(args, ":", &ptr)) && strcmp(arg, "auto")) {
 +        if ((ret = ff_parse_sample_format(&aconvert->out_sample_fmt, arg, ctx)) < 0)
 +            goto end;
 +    }
 +    if ((arg = av_strtok(NULL, ":", &ptr)) && strcmp(arg, "auto")) {
 +        if ((ret = ff_parse_channel_layout(&aconvert->out_chlayout, arg, ctx)) < 0)
 +            goto end;
 +    }
 +
 +end:
 +    av_freep(&args);
 +    return ret;
 +}
 +
 +static av_cold void uninit(AVFilterContext *ctx)
 +{
 +    AConvertContext *aconvert = ctx->priv;
 +    swr_free(&aconvert->swr);
 +}
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    AVFilterFormats *formats = NULL;
 +    AConvertContext *aconvert = ctx->priv;
 +    AVFilterLink *inlink  = ctx->inputs[0];
 +    AVFilterLink *outlink = ctx->outputs[0];
 +    AVFilterChannelLayouts *layouts;
 +
 +    ff_formats_ref(ff_all_formats(AVMEDIA_TYPE_AUDIO),
 +                         &inlink->out_formats);
 +    if (aconvert->out_sample_fmt != AV_SAMPLE_FMT_NONE) {
 +        formats = NULL;
 +        ff_add_format(&formats, aconvert->out_sample_fmt);
 +        ff_formats_ref(formats, &outlink->in_formats);
 +    } else
 +        ff_formats_ref(ff_all_formats(AVMEDIA_TYPE_AUDIO),
 +                             &outlink->in_formats);
 +
 +    ff_channel_layouts_ref(ff_all_channel_layouts(),
 +                         &inlink->out_channel_layouts);
 +    if (aconvert->out_chlayout != 0) {
 +        layouts = NULL;
 +        ff_add_channel_layout(&layouts, aconvert->out_chlayout);
 +        ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts);
 +    } else
 +        ff_channel_layouts_ref(ff_all_channel_layouts(),
 +                             &outlink->in_channel_layouts);
 +
 +    return 0;
 +}
 +
 +static int config_output(AVFilterLink *outlink)
 +{
 +    int ret;
 +    AVFilterContext *ctx = outlink->src;
 +    AVFilterLink *inlink = ctx->inputs[0];
 +    AConvertContext *aconvert = ctx->priv;
 +    char buf1[64], buf2[64];
 +
 +    /* if not specified in args, use the format and layout of the output */
 +    if (aconvert->out_sample_fmt == AV_SAMPLE_FMT_NONE)
 +        aconvert->out_sample_fmt = outlink->format;
 +    if (aconvert->out_chlayout   == 0)
 +        aconvert->out_chlayout   = outlink->channel_layout;
 +
 +    aconvert->swr = swr_alloc_set_opts(aconvert->swr,
 +                                       aconvert->out_chlayout, aconvert->out_sample_fmt, inlink->sample_rate,
 +                                       inlink->channel_layout, inlink->format,           inlink->sample_rate,
 +                                       0, ctx);
 +    if (!aconvert->swr)
 +        return AVERROR(ENOMEM);
 +    ret = swr_init(aconvert->swr);
 +    if (ret < 0)
 +        return ret;
 +
 +    av_get_channel_layout_string(buf1, sizeof(buf1),
 +                                 -1, inlink ->channel_layout);
 +    av_get_channel_layout_string(buf2, sizeof(buf2),
 +                                 -1, outlink->channel_layout);
 +    av_log(ctx, AV_LOG_INFO,
 +           "fmt:%s cl:%s -> fmt:%s cl:%s\n",
 +           av_get_sample_fmt_name(inlink ->format), buf1,
 +           av_get_sample_fmt_name(outlink->format), buf2);
 +
 +    return 0;
 +}
 +
-     ff_filter_samples(outlink, outsamplesref);
++static int  filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref)
 +{
 +    AConvertContext *aconvert = inlink->dst->priv;
 +    const int n = insamplesref->audio->nb_samples;
 +    AVFilterLink *const outlink = inlink->dst->outputs[0];
 +    AVFilterBufferRef *outsamplesref = ff_get_audio_buffer(outlink, AV_PERM_WRITE, n);
++    int ret;
 +
 +    swr_convert(aconvert->swr, outsamplesref->data, n,
 +                        (void *)insamplesref->data, n);
 +
 +    avfilter_copy_buffer_ref_props(outsamplesref, insamplesref);
 +    outsamplesref->audio->channel_layout = outlink->channel_layout;
 +
++    ret = ff_filter_samples(outlink, outsamplesref);
 +    avfilter_unref_buffer(insamplesref);
++    return ret;
 +}
 +
 +AVFilter avfilter_af_aconvert = {
 +    .name          = "aconvert",
 +    .description   = NULL_IF_CONFIG_SMALL("Convert the input audio to sample_fmt:channel_layout."),
 +    .priv_size     = sizeof(AConvertContext),
 +    .init          = init,
 +    .uninit        = uninit,
 +    .query_formats = query_formats,
 +
 +    .inputs    = (const AVFilterPad[]) {{ .name      = "default",
 +                                    .type            = AVMEDIA_TYPE_AUDIO,
 +                                    .filter_samples  = filter_samples,
 +                                    .min_perms       = AV_PERM_READ, },
 +                                  { .name = NULL}},
 +    .outputs   = (const AVFilterPad[]) {{ .name      = "default",
 +                                    .type            = AVMEDIA_TYPE_AUDIO,
 +                                    .config_props    = config_output, },
 +                                  { .name = NULL}},
 +};
index 802188d,0000000..660ae5d
mode 100644,000000..100644
--- /dev/null
@@@ -1,337 -1,0 +1,337 @@@
- static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +/*
 + * Copyright (c) 2011 Nicolas George <nicolas.george@normalesup.org>
 + *
 + * 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 merging filter
 + */
 +
 +#include "libavutil/audioconvert.h"
 +#include "libavutil/bprint.h"
 +#include "libavutil/opt.h"
 +#include "libswresample/swresample.h" // only for SWR_CH_MAX
 +#include "avfilter.h"
 +#include "audio.h"
 +#include "bufferqueue.h"
 +#include "internal.h"
 +
 +typedef struct {
 +    const AVClass *class;
 +    int nb_inputs;
 +    int route[SWR_CH_MAX]; /**< channels routing, see copy_samples */
 +    int bps;
 +    struct amerge_input {
 +        struct FFBufQueue queue;
 +        int nb_ch;         /**< number of channels for the input */
 +        int nb_samples;
 +        int pos;
 +    } *in;
 +} AMergeContext;
 +
 +#define OFFSET(x) offsetof(AMergeContext, x)
 +
 +static const AVOption amerge_options[] = {
 +    { "inputs", "specify the number of inputs", OFFSET(nb_inputs),
 +      AV_OPT_TYPE_INT, { .dbl = 2 }, 2, SWR_CH_MAX },
 +    {0}
 +};
 +
 +AVFILTER_DEFINE_CLASS(amerge);
 +
 +static av_cold void uninit(AVFilterContext *ctx)
 +{
 +    AMergeContext *am = ctx->priv;
 +    int i;
 +
 +    for (i = 0; i < am->nb_inputs; i++)
 +        ff_bufqueue_discard_all(&am->in[i].queue);
 +    av_freep(&am->in);
 +}
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    AMergeContext *am = ctx->priv;
 +    int64_t inlayout[SWR_CH_MAX], outlayout = 0;
 +    AVFilterFormats *formats;
 +    AVFilterChannelLayouts *layouts;
 +    int i, overlap = 0, nb_ch = 0;
 +
 +    for (i = 0; i < am->nb_inputs; i++) {
 +        if (!ctx->inputs[i]->in_channel_layouts ||
 +            !ctx->inputs[i]->in_channel_layouts->nb_channel_layouts) {
 +            av_log(ctx, AV_LOG_ERROR,
 +                   "No channel layout for input %d\n", i + 1);
 +            return AVERROR(EINVAL);
 +        }
 +        inlayout[i] = ctx->inputs[i]->in_channel_layouts->channel_layouts[0];
 +        if (ctx->inputs[i]->in_channel_layouts->nb_channel_layouts > 1) {
 +            char buf[256];
 +            av_get_channel_layout_string(buf, sizeof(buf), 0, inlayout[i]);
 +            av_log(ctx, AV_LOG_INFO, "Using \"%s\" for input %d\n", buf, i + 1);
 +        }
 +        am->in[i].nb_ch = av_get_channel_layout_nb_channels(inlayout[i]);
 +        if (outlayout & inlayout[i])
 +            overlap++;
 +        outlayout |= inlayout[i];
 +        nb_ch += am->in[i].nb_ch;
 +    }
 +    if (nb_ch > SWR_CH_MAX) {
 +        av_log(ctx, AV_LOG_ERROR, "Too many channels (max %d)\n", SWR_CH_MAX);
 +        return AVERROR(EINVAL);
 +    }
 +    if (overlap) {
 +        av_log(ctx, AV_LOG_WARNING,
 +               "Inputs overlap: output layout will be meaningless\n");
 +        for (i = 0; i < nb_ch; i++)
 +            am->route[i] = i;
 +        outlayout = av_get_default_channel_layout(nb_ch);
 +        if (!outlayout)
 +            outlayout = ((int64_t)1 << nb_ch) - 1;
 +    } else {
 +        int *route[SWR_CH_MAX];
 +        int c, out_ch_number = 0;
 +
 +        route[0] = am->route;
 +        for (i = 1; i < am->nb_inputs; i++)
 +            route[i] = route[i - 1] + am->in[i - 1].nb_ch;
 +        for (c = 0; c < 64; c++)
 +            for (i = 0; i < am->nb_inputs; i++)
 +                if ((inlayout[i] >> c) & 1)
 +                    *(route[i]++) = out_ch_number++;
 +    }
 +    formats = ff_make_format_list(ff_packed_sample_fmts_array);
 +    ff_set_common_formats(ctx, formats);
 +    for (i = 0; i < am->nb_inputs; i++) {
 +        layouts = NULL;
 +        ff_add_channel_layout(&layouts, inlayout[i]);
 +        ff_channel_layouts_ref(layouts, &ctx->inputs[i]->out_channel_layouts);
 +    }
 +    layouts = NULL;
 +    ff_add_channel_layout(&layouts, outlayout);
 +    ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts);
 +    ff_set_common_samplerates(ctx, ff_all_samplerates());
 +    return 0;
 +}
 +
 +static int config_output(AVFilterLink *outlink)
 +{
 +    AVFilterContext *ctx = outlink->src;
 +    AMergeContext *am = ctx->priv;
 +    AVBPrint bp;
 +    int i;
 +
 +    for (i = 1; i < am->nb_inputs; i++) {
 +        if (ctx->inputs[i]->sample_rate != ctx->inputs[0]->sample_rate) {
 +            av_log(ctx, AV_LOG_ERROR,
 +                   "Inputs must have the same sample rate "
 +                   "%d for in%d vs %d\n",
 +                   ctx->inputs[i]->sample_rate, i, ctx->inputs[0]->sample_rate);
 +            return AVERROR(EINVAL);
 +        }
 +    }
 +    am->bps = av_get_bytes_per_sample(ctx->outputs[0]->format);
 +    outlink->sample_rate = ctx->inputs[0]->sample_rate;
 +    outlink->time_base   = ctx->inputs[0]->time_base;
 +
 +    av_bprint_init(&bp, 0, 1);
 +    for (i = 0; i < am->nb_inputs; i++) {
 +        av_bprintf(&bp, "%sin%d:", i ? " + " : "", i);
 +        av_bprint_channel_layout(&bp, -1, ctx->inputs[i]->channel_layout);
 +    }
 +    av_bprintf(&bp, " -> out:");
 +    av_bprint_channel_layout(&bp, -1, ctx->outputs[0]->channel_layout);
 +    av_log(ctx, AV_LOG_INFO, "%s\n", bp.str);
 +
 +    return 0;
 +}
 +
 +static int request_frame(AVFilterLink *outlink)
 +{
 +    AVFilterContext *ctx = outlink->src;
 +    AMergeContext *am = ctx->priv;
 +    int i, ret;
 +
 +    for (i = 0; i < am->nb_inputs; i++)
 +        if (!am->in[i].nb_samples)
 +            if ((ret = ff_request_frame(ctx->inputs[i])) < 0)
 +                return ret;
 +    return 0;
 +}
 +
 +/**
 + * Copy samples from several input streams to one output stream.
 + * @param nb_inputs number of inputs
 + * @param in        inputs; used only for the nb_ch field;
 + * @param route     routing values;
 + *                  input channel i goes to output channel route[i];
 + *                  i <  in[0].nb_ch are the channels from the first output;
 + *                  i >= in[0].nb_ch are the channels from the second output
 + * @param ins       pointer to the samples of each inputs, in packed format;
 + *                  will be left at the end of the copied samples
 + * @param outs      pointer to the samples of the output, in packet format;
 + *                  must point to a buffer big enough;
 + *                  will be left at the end of the copied samples
 + * @param ns        number of samples to copy
 + * @param bps       bytes per sample
 + */
 +static inline void copy_samples(int nb_inputs, struct amerge_input in[],
 +                                int *route, uint8_t *ins[],
 +                                uint8_t **outs, int ns, int bps)
 +{
 +    int *route_cur;
 +    int i, c, nb_ch = 0;
 +
 +    for (i = 0; i < nb_inputs; i++)
 +        nb_ch += in[i].nb_ch;
 +    while (ns--) {
 +        route_cur = route;
 +        for (i = 0; i < nb_inputs; i++) {
 +            for (c = 0; c < in[i].nb_ch; c++) {
 +                memcpy((*outs) + bps * *(route_cur++), ins[i], bps);
 +                ins[i] += bps;
 +            }
 +        }
 +        *outs += nb_ch * bps;
 +    }
 +}
 +
-         return;
++static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +{
 +    AVFilterContext *ctx = inlink->dst;
 +    AMergeContext *am = ctx->priv;
 +    AVFilterLink *const outlink = ctx->outputs[0];
 +    int input_number;
 +    int nb_samples, ns, i;
 +    AVFilterBufferRef *outbuf, *inbuf[SWR_CH_MAX];
 +    uint8_t *ins[SWR_CH_MAX], *outs;
 +
 +    for (input_number = 0; input_number < am->nb_inputs; input_number++)
 +        if (inlink == ctx->inputs[input_number])
 +            break;
 +    av_assert1(input_number < am->nb_inputs);
 +    ff_bufqueue_add(ctx, &am->in[input_number].queue, insamples);
 +    am->in[input_number].nb_samples += insamples->audio->nb_samples;
 +    nb_samples = am->in[0].nb_samples;
 +    for (i = 1; i < am->nb_inputs; i++)
 +        nb_samples = FFMIN(nb_samples, am->in[i].nb_samples);
 +    if (!nb_samples)
-     ff_filter_samples(ctx->outputs[0], outbuf);
++        return 0;
 +
 +    outbuf = ff_get_audio_buffer(ctx->outputs[0], AV_PERM_WRITE, nb_samples);
 +    outs = outbuf->data[0];
 +    for (i = 0; i < am->nb_inputs; i++) {
 +        inbuf[i] = ff_bufqueue_peek(&am->in[i].queue, 0);
 +        ins[i] = inbuf[i]->data[0] +
 +                 am->in[i].pos * am->in[i].nb_ch * am->bps;
 +    }
 +    outbuf->pts = inbuf[0]->pts == AV_NOPTS_VALUE ? AV_NOPTS_VALUE :
 +                  inbuf[0]->pts +
 +                  av_rescale_q(am->in[0].pos,
 +                               (AVRational){ 1, ctx->inputs[0]->sample_rate },
 +                               ctx->outputs[0]->time_base);
 +
 +    avfilter_copy_buffer_ref_props(outbuf, inbuf[0]);
 +    outbuf->audio->nb_samples     = nb_samples;
 +    outbuf->audio->channel_layout = outlink->channel_layout;
 +
 +    while (nb_samples) {
 +        ns = nb_samples;
 +        for (i = 0; i < am->nb_inputs; i++)
 +            ns = FFMIN(ns, inbuf[i]->audio->nb_samples - am->in[i].pos);
 +        /* Unroll the most common sample formats: speed +~350% for the loop,
 +           +~13% overall (including two common decoders) */
 +        switch (am->bps) {
 +            case 1:
 +                copy_samples(am->nb_inputs, am->in, am->route, ins, &outs, ns, 1);
 +                break;
 +            case 2:
 +                copy_samples(am->nb_inputs, am->in, am->route, ins, &outs, ns, 2);
 +                break;
 +            case 4:
 +                copy_samples(am->nb_inputs, am->in, am->route, ins, &outs, ns, 4);
 +                break;
 +            default:
 +                copy_samples(am->nb_inputs, am->in, am->route, ins, &outs, ns, am->bps);
 +                break;
 +        }
 +
 +        nb_samples -= ns;
 +        for (i = 0; i < am->nb_inputs; i++) {
 +            am->in[i].nb_samples -= ns;
 +            am->in[i].pos += ns;
 +            if (am->in[i].pos == inbuf[i]->audio->nb_samples) {
 +                am->in[i].pos = 0;
 +                avfilter_unref_buffer(inbuf[i]);
 +                ff_bufqueue_get(&am->in[i].queue);
 +                inbuf[i] = ff_bufqueue_peek(&am->in[i].queue, 0);
 +                ins[i] = inbuf[i] ? inbuf[i]->data[0] : NULL;
 +            }
 +        }
 +    }
++    return ff_filter_samples(ctx->outputs[0], outbuf);
 +}
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args)
 +{
 +    AMergeContext *am = ctx->priv;
 +    int ret, i;
 +    char name[16];
 +
 +    am->class = &amerge_class;
 +    av_opt_set_defaults(am);
 +    ret = av_set_options_string(am, args, "=", ":");
 +    if (ret < 0) {
 +        av_log(ctx, AV_LOG_ERROR, "Error parsing options: '%s'\n", args);
 +        return ret;
 +    }
 +    am->in = av_calloc(am->nb_inputs, sizeof(*am->in));
 +    if (!am->in)
 +        return AVERROR(ENOMEM);
 +    for (i = 0; i < am->nb_inputs; i++) {
 +        AVFilterPad pad = {
 +            .name             = name,
 +            .type             = AVMEDIA_TYPE_AUDIO,
 +            .filter_samples   = filter_samples,
 +            .min_perms        = AV_PERM_READ | AV_PERM_PRESERVE,
 +        };
 +        snprintf(name, sizeof(name), "in%d", i);
 +        ff_insert_inpad(ctx, i, &pad);
 +    }
 +    return 0;
 +}
 +
 +AVFilter avfilter_af_amerge = {
 +    .name          = "amerge",
 +    .description   = NULL_IF_CONFIG_SMALL("Merge two audio streams into "
 +                                          "a single multi-channel stream."),
 +    .priv_size     = sizeof(AMergeContext),
 +    .init          = init,
 +    .uninit        = uninit,
 +    .query_formats = query_formats,
 +
 +    .inputs    = (const AVFilterPad[]) { { .name = NULL } },
 +    .outputs   = (const AVFilterPad[]) {
 +        { .name             = "default",
 +          .type             = AVMEDIA_TYPE_AUDIO,
 +          .config_props     = config_output,
 +          .request_frame    = request_frame, },
 +        { .name = NULL }
 +    },
 +};
Simple merge
index 095a2b5,0000000..cf1d8df
mode 100644,000000..100644
--- /dev/null
@@@ -1,266 -1,0 +1,268 @@@
- static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref)
 +/*
 + * Copyright (c) 2011 Stefano Sabatini
 + * Copyright (c) 2011 Mina Nagy Zaki
 + *
 + * 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
 + * resampling audio filter
 + */
 +
 +#include "libavutil/audioconvert.h"
 +#include "libavutil/avstring.h"
 +#include "libavutil/opt.h"
 +#include "libavutil/samplefmt.h"
 +#include "libavutil/avassert.h"
 +#include "libswresample/swresample.h"
 +#include "avfilter.h"
 +#include "audio.h"
 +#include "internal.h"
 +
 +typedef struct {
 +    double ratio;
 +    struct SwrContext *swr;
 +    int64_t next_pts;
 +    int req_fullfilled;
 +} AResampleContext;
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args)
 +{
 +    AResampleContext *aresample = ctx->priv;
 +    int ret = 0;
 +    char *argd = av_strdup(args);
 +
 +    aresample->next_pts = AV_NOPTS_VALUE;
 +    aresample->swr = swr_alloc();
 +    if (!aresample->swr)
 +        return AVERROR(ENOMEM);
 +
 +    if (args) {
 +        char *ptr=argd, *token;
 +
 +        while(token = av_strtok(ptr, ":", &ptr)) {
 +            char *value;
 +            av_strtok(token, "=", &value);
 +
 +            if(value) {
 +                if((ret=av_opt_set(aresample->swr, token, value, 0)) < 0)
 +                    goto end;
 +            } else {
 +                int out_rate;
 +                if ((ret = ff_parse_sample_rate(&out_rate, token, ctx)) < 0)
 +                    goto end;
 +                if((ret = av_opt_set_int(aresample->swr, "osr", out_rate, 0)) < 0)
 +                    goto end;
 +            }
 +        }
 +    }
 +end:
 +    av_free(argd);
 +    return ret;
 +}
 +
 +static av_cold void uninit(AVFilterContext *ctx)
 +{
 +    AResampleContext *aresample = ctx->priv;
 +    swr_free(&aresample->swr);
 +}
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    AResampleContext *aresample = ctx->priv;
 +    int out_rate                   = av_get_int(aresample->swr, "osr", NULL);
 +    uint64_t out_layout            = av_get_int(aresample->swr, "ocl", NULL);
 +    enum AVSampleFormat out_format = av_get_int(aresample->swr, "osf", NULL);
 +
 +    AVFilterLink *inlink  = ctx->inputs[0];
 +    AVFilterLink *outlink = ctx->outputs[0];
 +
 +    AVFilterFormats        *in_formats      = ff_all_formats(AVMEDIA_TYPE_AUDIO);
 +    AVFilterFormats        *out_formats;
 +    AVFilterFormats        *in_samplerates  = ff_all_samplerates();
 +    AVFilterFormats        *out_samplerates;
 +    AVFilterChannelLayouts *in_layouts      = ff_all_channel_layouts();
 +    AVFilterChannelLayouts *out_layouts;
 +
 +    ff_formats_ref  (in_formats,      &inlink->out_formats);
 +    ff_formats_ref  (in_samplerates,  &inlink->out_samplerates);
 +    ff_channel_layouts_ref(in_layouts,      &inlink->out_channel_layouts);
 +
 +    if(out_rate > 0) {
 +        out_samplerates = ff_make_format_list((int[]){ out_rate, -1 });
 +    } else {
 +        out_samplerates = ff_all_samplerates();
 +    }
 +    ff_formats_ref(out_samplerates, &outlink->in_samplerates);
 +
 +    if(out_format != AV_SAMPLE_FMT_NONE) {
 +        out_formats = ff_make_format_list((int[]){ out_format, -1 });
 +    } else
 +        out_formats = ff_all_formats(AVMEDIA_TYPE_AUDIO);
 +    ff_formats_ref(out_formats, &outlink->in_formats);
 +
 +    if(out_layout) {
 +        out_layouts = avfilter_make_format64_list((int64_t[]){ out_layout, -1 });
 +    } else
 +        out_layouts = ff_all_channel_layouts();
 +    ff_channel_layouts_ref(out_layouts, &outlink->in_channel_layouts);
 +
 +    return 0;
 +}
 +
 +
 +static int config_output(AVFilterLink *outlink)
 +{
 +    int ret;
 +    AVFilterContext *ctx = outlink->src;
 +    AVFilterLink *inlink = ctx->inputs[0];
 +    AResampleContext *aresample = ctx->priv;
 +    int out_rate;
 +    uint64_t out_layout;
 +    enum AVSampleFormat out_format;
 +    char inchl_buf[128], outchl_buf[128];
 +
 +    aresample->swr = swr_alloc_set_opts(aresample->swr,
 +                                        outlink->channel_layout, outlink->format, outlink->sample_rate,
 +                                        inlink->channel_layout, inlink->format, inlink->sample_rate,
 +                                        0, ctx);
 +    if (!aresample->swr)
 +        return AVERROR(ENOMEM);
 +
 +    ret = swr_init(aresample->swr);
 +    if (ret < 0)
 +        return ret;
 +
 +    out_rate   = av_get_int(aresample->swr, "osr", NULL);
 +    out_layout = av_get_int(aresample->swr, "ocl", NULL);
 +    out_format = av_get_int(aresample->swr, "osf", NULL);
 +    outlink->time_base = (AVRational) {1, out_rate};
 +
 +    av_assert0(outlink->sample_rate == out_rate);
 +    av_assert0(outlink->channel_layout == out_layout);
 +    av_assert0(outlink->format == out_format);
 +
 +    aresample->ratio = (double)outlink->sample_rate / inlink->sample_rate;
 +
 +    av_get_channel_layout_string(inchl_buf,  sizeof(inchl_buf),  -1, inlink ->channel_layout);
 +    av_get_channel_layout_string(outchl_buf, sizeof(outchl_buf), -1, outlink->channel_layout);
 +
 +    av_log(ctx, AV_LOG_INFO, "chl:%s fmt:%s r:%dHz -> chl:%s fmt:%s r:%dHz\n",
 +           inchl_buf,  av_get_sample_fmt_name(inlink->format),  inlink->sample_rate,
 +           outchl_buf, av_get_sample_fmt_name(outlink->format), outlink->sample_rate);
 +    return 0;
 +}
 +
-         return;
++static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref)
 +{
 +    AResampleContext *aresample = inlink->dst->priv;
 +    const int n_in  = insamplesref->audio->nb_samples;
 +    int n_out       = n_in * aresample->ratio * 2 ;
 +    AVFilterLink *const outlink = inlink->dst->outputs[0];
 +    AVFilterBufferRef *outsamplesref = ff_get_audio_buffer(outlink, AV_PERM_WRITE, n_out);
++    int ret;
 +
 +
 +    avfilter_copy_buffer_ref_props(outsamplesref, insamplesref);
 +
 +    if(insamplesref->pts != AV_NOPTS_VALUE) {
 +        int64_t inpts = av_rescale(insamplesref->pts, inlink->time_base.num * (int64_t)outlink->sample_rate * inlink->sample_rate, inlink->time_base.den);
 +        int64_t outpts= swr_next_pts(aresample->swr, inpts);
 +        aresample->next_pts =
 +        outsamplesref->pts  = (outpts + inlink->sample_rate/2) / inlink->sample_rate;
 +    } else {
 +        outsamplesref->pts  = AV_NOPTS_VALUE;
 +    }
 +
 +    n_out = swr_convert(aresample->swr, outsamplesref->extended_data, n_out,
 +                                 (void *)insamplesref->extended_data, n_in);
 +    if (n_out <= 0) {
 +        avfilter_unref_buffer(outsamplesref);
 +        avfilter_unref_buffer(insamplesref);
-     ff_filter_samples(outlink, outsamplesref);
++        return 0;
 +    }
 +
 +    outsamplesref->audio->sample_rate = outlink->sample_rate;
 +    outsamplesref->audio->nb_samples  = n_out;
 +
++    ret = ff_filter_samples(outlink, outsamplesref);
 +    aresample->req_fullfilled= 1;
 +    avfilter_unref_buffer(insamplesref);
++    return ret;
 +}
 +
 +static int request_frame(AVFilterLink *outlink)
 +{
 +    AVFilterContext *ctx = outlink->src;
 +    AResampleContext *aresample = ctx->priv;
 +    AVFilterLink *const inlink = outlink->src->inputs[0];
 +    int ret;
 +
 +    aresample->req_fullfilled = 0;
 +    do{
 +        ret = ff_request_frame(ctx->inputs[0]);
 +    }while(!aresample->req_fullfilled && ret>=0);
 +
 +    if (ret == AVERROR_EOF) {
 +        AVFilterBufferRef *outsamplesref;
 +        int n_out = 4096;
 +
 +        outsamplesref = ff_get_audio_buffer(outlink, AV_PERM_WRITE, n_out);
 +        if (!outsamplesref)
 +            return AVERROR(ENOMEM);
 +        n_out = swr_convert(aresample->swr, outsamplesref->extended_data, n_out, 0, 0);
 +        if (n_out <= 0) {
 +            avfilter_unref_buffer(outsamplesref);
 +            return (n_out == 0) ? AVERROR_EOF : n_out;
 +        }
 +
 +        outsamplesref->audio->sample_rate = outlink->sample_rate;
 +        outsamplesref->audio->nb_samples  = n_out;
 +#if 0
 +        outsamplesref->pts = aresample->next_pts;
 +        if(aresample->next_pts != AV_NOPTS_VALUE)
 +            aresample->next_pts += av_rescale_q(n_out, (AVRational){1 ,outlink->sample_rate}, outlink->time_base);
 +#else
 +        outsamplesref->pts = (swr_next_pts(aresample->swr, INT64_MIN) + inlink->sample_rate/2) / inlink->sample_rate;
 +#endif
 +
 +        ff_filter_samples(outlink, outsamplesref);
 +        return 0;
 +    }
 +    return ret;
 +}
 +
 +AVFilter avfilter_af_aresample = {
 +    .name          = "aresample",
 +    .description   = NULL_IF_CONFIG_SMALL("Resample audio data."),
 +    .init          = init,
 +    .uninit        = uninit,
 +    .query_formats = query_formats,
 +    .priv_size     = sizeof(AResampleContext),
 +
 +    .inputs    = (const AVFilterPad[]) {{ .name      = "default",
 +                                    .type            = AVMEDIA_TYPE_AUDIO,
 +                                    .filter_samples  = filter_samples,
 +                                    .min_perms       = AV_PERM_READ, },
 +                                  { .name = NULL}},
 +    .outputs   = (const AVFilterPad[]) {{ .name      = "default",
 +                                    .config_props    = config_output,
 +                                    .request_frame   = request_frame,
 +                                    .type            = AVMEDIA_TYPE_AUDIO, },
 +                                  { .name = NULL}},
 +};
index 7a6c381,0000000..95fd507
mode 100644,000000..100644
--- /dev/null
@@@ -1,204 -1,0 +1,205 @@@
- static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +/*
 + * Copyright (c) 2012 Andrey Utkin
 + * Copyright (c) 2012 Stefano Sabatini
 + *
 + * 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
 + * Filter that changes number of samples on single output operation
 + */
 +
 +#include "libavutil/audio_fifo.h"
 +#include "libavutil/audioconvert.h"
 +#include "libavutil/avassert.h"
 +#include "libavutil/opt.h"
 +#include "avfilter.h"
 +#include "audio.h"
 +#include "internal.h"
 +#include "formats.h"
 +
 +typedef struct {
 +    const AVClass *class;
 +    int nb_out_samples;  ///< how many samples to output
 +    AVAudioFifo *fifo;   ///< samples are queued here
 +    int64_t next_out_pts;
 +    int req_fullfilled;
 +    int pad;
 +} ASNSContext;
 +
 +#define OFFSET(x) offsetof(ASNSContext, x)
 +
 +static const AVOption asetnsamples_options[] = {
 +{ "pad", "pad last frame with zeros", OFFSET(pad), AV_OPT_TYPE_INT, {.dbl=1}, 0, 1 },
 +{ "p",   "pad last frame with zeros", OFFSET(pad), AV_OPT_TYPE_INT, {.dbl=1}, 0, 1 },
 +{ "nb_out_samples", "set the number of per-frame output samples", OFFSET(nb_out_samples), AV_OPT_TYPE_INT, {.dbl=1024}, 1, INT_MAX },
 +{ "n",              "set the number of per-frame output samples", OFFSET(nb_out_samples), AV_OPT_TYPE_INT, {.dbl=1024}, 1, INT_MAX },
 +{ NULL }
 +};
 +
 +AVFILTER_DEFINE_CLASS(asetnsamples);
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args)
 +{
 +    ASNSContext *asns = ctx->priv;
 +    int err;
 +
 +    asns->class = &asetnsamples_class;
 +    av_opt_set_defaults(asns);
 +
 +    if ((err = av_set_options_string(asns, args, "=", ":")) < 0) {
 +        av_log(ctx, AV_LOG_ERROR, "Error parsing options string: '%s'\n", args);
 +        return err;
 +    }
 +
 +    asns->next_out_pts = AV_NOPTS_VALUE;
 +    av_log(ctx, AV_LOG_INFO, "nb_out_samples:%d pad:%d\n", asns->nb_out_samples, asns->pad);
 +
 +    return 0;
 +}
 +
 +static av_cold void uninit(AVFilterContext *ctx)
 +{
 +    ASNSContext *asns = ctx->priv;
 +    av_audio_fifo_free(asns->fifo);
 +}
 +
 +static int config_props_output(AVFilterLink *outlink)
 +{
 +    ASNSContext *asns = outlink->src->priv;
 +    int nb_channels = av_get_channel_layout_nb_channels(outlink->channel_layout);
 +
 +    asns->fifo = av_audio_fifo_alloc(outlink->format, nb_channels, asns->nb_out_samples);
 +    if (!asns->fifo)
 +        return AVERROR(ENOMEM);
 +
 +    return 0;
 +}
 +
 +static int push_samples(AVFilterLink *outlink)
 +{
 +    ASNSContext *asns = outlink->src->priv;
 +    AVFilterBufferRef *outsamples = NULL;
 +    int nb_out_samples, nb_pad_samples;
 +
 +    if (asns->pad) {
 +        nb_out_samples = av_audio_fifo_size(asns->fifo) ? asns->nb_out_samples : 0;
 +        nb_pad_samples = nb_out_samples - FFMIN(nb_out_samples, av_audio_fifo_size(asns->fifo));
 +    } else {
 +        nb_out_samples = FFMIN(asns->nb_out_samples, av_audio_fifo_size(asns->fifo));
 +        nb_pad_samples = 0;
 +    }
 +
 +    if (!nb_out_samples)
 +        return 0;
 +
 +    outsamples = ff_get_audio_buffer(outlink, AV_PERM_WRITE, nb_out_samples);
 +    av_assert0(outsamples);
 +
 +    av_audio_fifo_read(asns->fifo,
 +                       (void **)outsamples->extended_data, nb_out_samples);
 +
 +    if (nb_pad_samples)
 +        av_samples_set_silence(outsamples->extended_data, nb_out_samples - nb_pad_samples,
 +                               nb_pad_samples, av_get_channel_layout_nb_channels(outlink->channel_layout),
 +                               outlink->format);
 +    outsamples->audio->nb_samples     = nb_out_samples;
 +    outsamples->audio->channel_layout = outlink->channel_layout;
 +    outsamples->audio->sample_rate    = outlink->sample_rate;
 +    outsamples->pts = asns->next_out_pts;
 +
 +    if (asns->next_out_pts != AV_NOPTS_VALUE)
 +        asns->next_out_pts += nb_out_samples;
 +
 +    ff_filter_samples(outlink, outsamples);
 +    asns->req_fullfilled = 1;
 +    return nb_out_samples;
 +}
 +
-             return;
++static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +{
 +    AVFilterContext *ctx = inlink->dst;
 +    ASNSContext *asns = ctx->priv;
 +    AVFilterLink *outlink = ctx->outputs[0];
 +    int ret;
 +    int nb_samples = insamples->audio->nb_samples;
 +
 +    if (av_audio_fifo_space(asns->fifo) < nb_samples) {
 +        av_log(ctx, AV_LOG_DEBUG, "No space for %d samples, stretching audio fifo\n", nb_samples);
 +        ret = av_audio_fifo_realloc(asns->fifo, av_audio_fifo_size(asns->fifo) + nb_samples);
 +        if (ret < 0) {
 +            av_log(ctx, AV_LOG_ERROR,
 +                   "Stretching audio fifo failed, discarded %d samples\n", nb_samples);
++            return -1;
 +        }
 +    }
 +    av_audio_fifo_write(asns->fifo, (void **)insamples->extended_data, nb_samples);
 +    if (asns->next_out_pts == AV_NOPTS_VALUE)
 +        asns->next_out_pts = insamples->pts;
 +    avfilter_unref_buffer(insamples);
 +
 +    if (av_audio_fifo_size(asns->fifo) >= asns->nb_out_samples)
 +        push_samples(outlink);
++    return 0;
 +}
 +
 +static int request_frame(AVFilterLink *outlink)
 +{
 +    ASNSContext *asns = outlink->src->priv;
 +    AVFilterLink *inlink = outlink->src->inputs[0];
 +    int ret;
 +
 +    asns->req_fullfilled = 0;
 +    do {
 +        ret = ff_request_frame(inlink);
 +    } while (!asns->req_fullfilled && ret >= 0);
 +
 +    if (ret == AVERROR_EOF)
 +        while (push_samples(outlink))
 +            ;
 +
 +    return ret;
 +}
 +
 +AVFilter avfilter_af_asetnsamples = {
 +    .name           = "asetnsamples",
 +    .description    = NULL_IF_CONFIG_SMALL("Set the number of samples for each output audio frames."),
 +    .priv_size      = sizeof(ASNSContext),
 +    .init           = init,
 +    .uninit         = uninit,
 +
 +    .inputs  = (const AVFilterPad[]) {
 +        {
 +            .name           = "default",
 +            .type           = AVMEDIA_TYPE_AUDIO,
 +            .filter_samples = filter_samples,
 +            .min_perms      = AV_PERM_READ|AV_PERM_WRITE
 +        },
 +        { .name = NULL }
 +    },
 +
 +    .outputs = (const AVFilterPad[]) {
 +        {
 +            .name           = "default",
 +            .type           = AVMEDIA_TYPE_AUDIO,
 +            .request_frame  = request_frame,
 +            .config_props   = config_props_output,
 +        },
 +        { .name = NULL }
 +    },
 +};
index d774ec7,0000000..0d4bbb2
mode 100644,000000..100644
--- /dev/null
@@@ -1,106 -1,0 +1,106 @@@
- static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref)
 +/*
 + * Copyright (c) 2011 Stefano Sabatini
 + *
 + * 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
 + * filter for showing textual audio frame information
 + */
 +
 +#include "libavutil/adler32.h"
 +#include "libavutil/audioconvert.h"
 +#include "libavutil/timestamp.h"
 +#include "audio.h"
 +#include "avfilter.h"
 +
 +typedef struct {
 +    unsigned int frame;
 +} ShowInfoContext;
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args)
 +{
 +    ShowInfoContext *showinfo = ctx->priv;
 +    showinfo->frame = 0;
 +    return 0;
 +}
 +
-     ff_filter_samples(inlink->dst->outputs[0], samplesref);
++static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref)
 +{
 +    AVFilterContext *ctx = inlink->dst;
 +    ShowInfoContext *showinfo = ctx->priv;
 +    uint32_t plane_checksum[8] = {0}, checksum = 0;
 +    char chlayout_str[128];
 +    int plane;
 +    int linesize =
 +        samplesref->audio->nb_samples *
 +        av_get_bytes_per_sample(samplesref->format);
 +    if (!av_sample_fmt_is_planar(samplesref->format))
 +        linesize *= av_get_channel_layout_nb_channels(samplesref->audio->channel_layout);
 +
 +    for (plane = 0; samplesref->data[plane] && plane < 8; plane++) {
 +        uint8_t *data = samplesref->data[plane];
 +
 +        plane_checksum[plane] = av_adler32_update(plane_checksum[plane],
 +                                                  data, linesize);
 +        checksum = av_adler32_update(checksum, data, linesize);
 +    }
 +
 +    av_get_channel_layout_string(chlayout_str, sizeof(chlayout_str), -1,
 +                                 samplesref->audio->channel_layout);
 +
 +    av_log(ctx, AV_LOG_INFO,
 +           "n:%d pts:%s pts_time:%s pos:%"PRId64" "
 +           "fmt:%s chlayout:%s nb_samples:%d rate:%d "
 +           "checksum:%08X plane_checksum[%08X",
 +           showinfo->frame,
 +           av_ts2str(samplesref->pts), av_ts2timestr(samplesref->pts, &inlink->time_base),
 +           samplesref->pos,
 +           av_get_sample_fmt_name(samplesref->format),
 +           chlayout_str,
 +           samplesref->audio->nb_samples,
 +           samplesref->audio->sample_rate,
 +           checksum,
 +           plane_checksum[0]);
 +
 +    for (plane = 1; samplesref->data[plane] && plane < 8; plane++)
 +        av_log(ctx, AV_LOG_INFO, " %08X", plane_checksum[plane]);
 +    av_log(ctx, AV_LOG_INFO, "]\n");
 +
 +    showinfo->frame++;
++    return ff_filter_samples(inlink->dst->outputs[0], samplesref);
 +}
 +
 +AVFilter avfilter_af_ashowinfo = {
 +    .name        = "ashowinfo",
 +    .description = NULL_IF_CONFIG_SMALL("Show textual information for each audio frame."),
 +
 +    .priv_size = sizeof(ShowInfoContext),
 +    .init      = init,
 +
 +    .inputs    = (const AVFilterPad[]) {{ .name       = "default",
 +                                    .type             = AVMEDIA_TYPE_AUDIO,
 +                                    .get_audio_buffer = ff_null_get_audio_buffer,
 +                                    .filter_samples   = filter_samples,
 +                                    .min_perms        = AV_PERM_READ, },
 +                                  { .name = NULL}},
 +
 +    .outputs   = (const AVFilterPad[]) {{ .name       = "default",
 +                                    .type             = AVMEDIA_TYPE_AUDIO },
 +                                  { .name = NULL}},
 +};
index 8cf3f39,0000000..587d9a7
mode 100644,000000..100644
--- /dev/null
@@@ -1,210 -1,0 +1,213 @@@
- static void send_out(AVFilterContext *ctx, int out_id)
 +/*
 + * Copyright (c) 2011 Nicolas George <nicolas.george@normalesup.org>
 + *
 + * 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
 + * Stream (de)synchronization filter
 + */
 +
 +#include "libavutil/eval.h"
 +#include "avfilter.h"
 +#include "audio.h"
 +#include "internal.h"
 +
 +#define QUEUE_SIZE 16
 +
 +static const char * const var_names[] = {
 +    "b1", "b2",
 +    "s1", "s2",
 +    "t1", "t2",
 +    NULL
 +};
 +
 +enum var_name {
 +    VAR_B1, VAR_B2,
 +    VAR_S1, VAR_S2,
 +    VAR_T1, VAR_T2,
 +    VAR_NB
 +};
 +
 +typedef struct {
 +    AVExpr *expr;
 +    double var_values[VAR_NB];
 +    struct buf_queue {
 +        AVFilterBufferRef *buf[QUEUE_SIZE];
 +        unsigned tail, nb;
 +        /* buf[tail] is the oldest,
 +           buf[(tail + nb) % QUEUE_SIZE] is where the next is added */
 +    } queue[2];
 +    int req[2];
 +    int next_out;
 +    int eof; /* bitmask, one bit for each stream */
 +} AStreamSyncContext;
 +
 +static const char *default_expr = "t1-t2";
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args0)
 +{
 +    AStreamSyncContext *as = ctx->priv;
 +    const char *expr = args0 ? args0 : default_expr;
 +    int r, i;
 +
 +    r = av_expr_parse(&as->expr, expr, var_names,
 +                      NULL, NULL, NULL, NULL, 0, ctx);
 +    if (r < 0) {
 +        av_log(ctx, AV_LOG_ERROR, "Error in expression \"%s\"\n", expr);
 +        return r;
 +    }
 +    for (i = 0; i < 42; i++)
 +        av_expr_eval(as->expr, as->var_values, NULL); /* exercize prng */
 +    return 0;
 +}
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    int i;
 +    AVFilterFormats *formats, *rates;
 +    AVFilterChannelLayouts *layouts;
 +
 +    for (i = 0; i < 2; i++) {
 +        formats = ctx->inputs[i]->in_formats;
 +        ff_formats_ref(formats, &ctx->inputs[i]->out_formats);
 +        ff_formats_ref(formats, &ctx->outputs[i]->in_formats);
 +        rates = ff_all_samplerates();
 +        ff_formats_ref(rates, &ctx->inputs[i]->out_samplerates);
 +        ff_formats_ref(rates, &ctx->outputs[i]->in_samplerates);
 +        layouts = ctx->inputs[i]->in_channel_layouts;
 +        ff_channel_layouts_ref(layouts, &ctx->inputs[i]->out_channel_layouts);
 +        ff_channel_layouts_ref(layouts, &ctx->outputs[i]->in_channel_layouts);
 +    }
 +    return 0;
 +}
 +
 +static int config_output(AVFilterLink *outlink)
 +{
 +    AVFilterContext *ctx = outlink->src;
 +    int id = outlink == ctx->outputs[1];
 +
 +    outlink->sample_rate = ctx->inputs[id]->sample_rate;
 +    outlink->time_base   = ctx->inputs[id]->time_base;
 +    return 0;
 +}
 +
-     ff_filter_samples(ctx->outputs[out_id], buf);
++static int send_out(AVFilterContext *ctx, int out_id)
 +{
 +    AStreamSyncContext *as = ctx->priv;
 +    struct buf_queue *queue = &as->queue[out_id];
 +    AVFilterBufferRef *buf = queue->buf[queue->tail];
++    int ret;
 +
 +    queue->buf[queue->tail] = NULL;
 +    as->var_values[VAR_B1 + out_id]++;
 +    as->var_values[VAR_S1 + out_id] += buf->audio->nb_samples;
 +    if (buf->pts != AV_NOPTS_VALUE)
 +        as->var_values[VAR_T1 + out_id] =
 +            av_q2d(ctx->outputs[out_id]->time_base) * buf->pts;
 +    as->var_values[VAR_T1 + out_id] += buf->audio->nb_samples /
 +                                   (double)ctx->inputs[out_id]->sample_rate;
- static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
++    ret = ff_filter_samples(ctx->outputs[out_id], buf);
 +    queue->nb--;
 +    queue->tail = (queue->tail + 1) % QUEUE_SIZE;
 +    if (as->req[out_id])
 +        as->req[out_id]--;
++    return ret;
 +}
 +
 +static void send_next(AVFilterContext *ctx)
 +{
 +    AStreamSyncContext *as = ctx->priv;
 +    int i;
 +
 +    while (1) {
 +        if (!as->queue[as->next_out].nb)
 +            break;
 +        send_out(ctx, as->next_out);
 +        if (!as->eof)
 +            as->next_out = av_expr_eval(as->expr, as->var_values, NULL) >= 0;
 +    }
 +    for (i = 0; i < 2; i++)
 +        if (as->queue[i].nb == QUEUE_SIZE)
 +            send_out(ctx, i);
 +}
 +
 +static int request_frame(AVFilterLink *outlink)
 +{
 +    AVFilterContext *ctx = outlink->src;
 +    AStreamSyncContext *as = ctx->priv;
 +    int id = outlink == ctx->outputs[1];
 +
 +    as->req[id]++;
 +    while (as->req[id] && !(as->eof & (1 << id))) {
 +        if (as->queue[as->next_out].nb) {
 +            send_next(ctx);
 +        } else {
 +            as->eof |= 1 << as->next_out;
 +            ff_request_frame(ctx->inputs[as->next_out]);
 +            if (as->eof & (1 << as->next_out))
 +                as->next_out = !as->next_out;
 +        }
 +    }
 +    return 0;
 +}
 +
++static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +{
 +    AVFilterContext *ctx = inlink->dst;
 +    AStreamSyncContext *as = ctx->priv;
 +    int id = inlink == ctx->inputs[1];
 +
 +    as->queue[id].buf[(as->queue[id].tail + as->queue[id].nb++) % QUEUE_SIZE] =
 +        insamples;
 +    as->eof &= ~(1 << id);
 +    send_next(ctx);
++    return 0;
 +}
 +
 +AVFilter avfilter_af_astreamsync = {
 +    .name          = "astreamsync",
 +    .description   = NULL_IF_CONFIG_SMALL("Copy two streams of audio data "
 +                                          "in a configurable order."),
 +    .priv_size     = sizeof(AStreamSyncContext),
 +    .init          = init,
 +    .query_formats = query_formats,
 +
 +    .inputs    = (const AVFilterPad[]) {
 +        { .name             = "in1",
 +          .type             = AVMEDIA_TYPE_AUDIO,
 +          .filter_samples   = filter_samples,
 +          .min_perms        = AV_PERM_READ, },
 +        { .name             = "in2",
 +          .type             = AVMEDIA_TYPE_AUDIO,
 +          .filter_samples   = filter_samples,
 +          .min_perms        = AV_PERM_READ, },
 +        { .name = NULL }
 +    },
 +    .outputs   = (const AVFilterPad[]) {
 +        { .name             = "out1",
 +          .type             = AVMEDIA_TYPE_AUDIO,
 +          .config_props     = config_output,
 +          .request_frame    = request_frame, },
 +        { .name             = "out2",
 +          .type             = AVMEDIA_TYPE_AUDIO,
 +          .config_props     = config_output,
 +          .request_frame    = request_frame, },
 +        { .name = NULL }
 +    },
 +};
Simple merge
index 7a08503,0000000..959cacb
mode 100644,000000..100644
--- /dev/null
@@@ -1,1161 -1,0 +1,1162 @@@
- static void filter_samples(AVFilterLink *inlink,
 +/*
 + * Copyright (c) 2012 Pavel Koshevoy <pkoshevoy at gmail dot com>
 + *
 + * 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
 + * tempo scaling audio filter -- an implementation of WSOLA algorithm
 + *
 + * Based on MIT licensed yaeAudioTempoFilter.h and yaeAudioFragment.h
 + * from Apprentice Video player by Pavel Koshevoy.
 + * https://sourceforge.net/projects/apprenticevideo/
 + *
 + * An explanation of SOLA algorithm is available at
 + * http://www.surina.net/article/time-and-pitch-scaling.html
 + *
 + * WSOLA is very similar to SOLA, only one major difference exists between
 + * these algorithms.  SOLA shifts audio fragments along the output stream,
 + * where as WSOLA shifts audio fragments along the input stream.
 + *
 + * The advantage of WSOLA algorithm is that the overlap region size is
 + * always the same, therefore the blending function is constant and
 + * can be precomputed.
 + */
 +
 +#include <float.h>
 +#include "libavcodec/avfft.h"
 +#include "libavutil/audioconvert.h"
 +#include "libavutil/avassert.h"
 +#include "libavutil/avstring.h"
 +#include "libavutil/eval.h"
 +#include "libavutil/opt.h"
 +#include "libavutil/samplefmt.h"
 +#include "avfilter.h"
 +#include "audio.h"
 +#include "internal.h"
 +
 +/**
 + * A fragment of audio waveform
 + */
 +typedef struct {
 +    // index of the first sample of this fragment in the overall waveform;
 +    // 0: input sample position
 +    // 1: output sample position
 +    int64_t position[2];
 +
 +    // original packed multi-channel samples:
 +    uint8_t *data;
 +
 +    // number of samples in this fragment:
 +    int nsamples;
 +
 +    // rDFT transform of the down-mixed mono fragment, used for
 +    // fast waveform alignment via correlation in frequency domain:
 +    FFTSample *xdat;
 +} AudioFragment;
 +
 +/**
 + * Filter state machine states
 + */
 +typedef enum {
 +    YAE_LOAD_FRAGMENT,
 +    YAE_ADJUST_POSITION,
 +    YAE_RELOAD_FRAGMENT,
 +    YAE_OUTPUT_OVERLAP_ADD,
 +    YAE_FLUSH_OUTPUT,
 +} FilterState;
 +
 +/**
 + * Filter state machine
 + */
 +typedef struct {
 +    // ring-buffer of input samples, necessary because some times
 +    // input fragment position may be adjusted backwards:
 +    uint8_t *buffer;
 +
 +    // ring-buffer maximum capacity, expressed in sample rate time base:
 +    int ring;
 +
 +    // ring-buffer house keeping:
 +    int size;
 +    int head;
 +    int tail;
 +
 +    // 0: input sample position corresponding to the ring buffer tail
 +    // 1: output sample position
 +    int64_t position[2];
 +
 +    // sample format:
 +    enum AVSampleFormat format;
 +
 +    // number of channels:
 +    int channels;
 +
 +    // row of bytes to skip from one sample to next, across multple channels;
 +    // stride = (number-of-channels * bits-per-sample-per-channel) / 8
 +    int stride;
 +
 +    // fragment window size, power-of-two integer:
 +    int window;
 +
 +    // Hann window coefficients, for feathering
 +    // (blending) the overlapping fragment region:
 +    float *hann;
 +
 +    // tempo scaling factor:
 +    double tempo;
 +
 +    // cumulative alignment drift:
 +    int drift;
 +
 +    // current/previous fragment ring-buffer:
 +    AudioFragment frag[2];
 +
 +    // current fragment index:
 +    uint64_t nfrag;
 +
 +    // current state:
 +    FilterState state;
 +
 +    // for fast correlation calculation in frequency domain:
 +    RDFTContext *real_to_complex;
 +    RDFTContext *complex_to_real;
 +    FFTSample *correlation;
 +
 +    // for managing AVFilterPad.request_frame and AVFilterPad.filter_samples
 +    int request_fulfilled;
 +    AVFilterBufferRef *dst_buffer;
 +    uint8_t *dst;
 +    uint8_t *dst_end;
 +    uint64_t nsamples_in;
 +    uint64_t nsamples_out;
 +} ATempoContext;
 +
 +/**
 + * Reset filter to initial state, do not deallocate existing local buffers.
 + */
 +static void yae_clear(ATempoContext *atempo)
 +{
 +    atempo->size = 0;
 +    atempo->head = 0;
 +    atempo->tail = 0;
 +
 +    atempo->drift = 0;
 +    atempo->nfrag = 0;
 +    atempo->state = YAE_LOAD_FRAGMENT;
 +
 +    atempo->position[0] = 0;
 +    atempo->position[1] = 0;
 +
 +    atempo->frag[0].position[0] = 0;
 +    atempo->frag[0].position[1] = 0;
 +    atempo->frag[0].nsamples    = 0;
 +
 +    atempo->frag[1].position[0] = 0;
 +    atempo->frag[1].position[1] = 0;
 +    atempo->frag[1].nsamples    = 0;
 +
 +    // shift left position of 1st fragment by half a window
 +    // so that no re-normalization would be required for
 +    // the left half of the 1st fragment:
 +    atempo->frag[0].position[0] = -(int64_t)(atempo->window / 2);
 +    atempo->frag[0].position[1] = -(int64_t)(atempo->window / 2);
 +
 +    avfilter_unref_bufferp(&atempo->dst_buffer);
 +    atempo->dst     = NULL;
 +    atempo->dst_end = NULL;
 +
 +    atempo->request_fulfilled = 0;
 +    atempo->nsamples_in       = 0;
 +    atempo->nsamples_out      = 0;
 +}
 +
 +/**
 + * Reset filter to initial state and deallocate all buffers.
 + */
 +static void yae_release_buffers(ATempoContext *atempo)
 +{
 +    yae_clear(atempo);
 +
 +    av_freep(&atempo->frag[0].data);
 +    av_freep(&atempo->frag[1].data);
 +    av_freep(&atempo->frag[0].xdat);
 +    av_freep(&atempo->frag[1].xdat);
 +
 +    av_freep(&atempo->buffer);
 +    av_freep(&atempo->hann);
 +    av_freep(&atempo->correlation);
 +
 +    av_rdft_end(atempo->real_to_complex);
 +    atempo->real_to_complex = NULL;
 +
 +    av_rdft_end(atempo->complex_to_real);
 +    atempo->complex_to_real = NULL;
 +}
 +
 +#define REALLOC_OR_FAIL(field, field_size)                      \
 +    do {                                                        \
 +        void * new_field = av_realloc(field, (field_size));     \
 +        if (!new_field) {                                       \
 +            yae_release_buffers(atempo);                        \
 +            return AVERROR(ENOMEM);                             \
 +        }                                                       \
 +        field = new_field;                                      \
 +    } while (0)
 +
 +/**
 + * Prepare filter for processing audio data of given format,
 + * sample rate and number of channels.
 + */
 +static int yae_reset(ATempoContext *atempo,
 +                     enum AVSampleFormat format,
 +                     int sample_rate,
 +                     int channels)
 +{
 +    const int sample_size = av_get_bytes_per_sample(format);
 +    uint32_t nlevels  = 0;
 +    uint32_t pot;
 +    int i;
 +
 +    atempo->format   = format;
 +    atempo->channels = channels;
 +    atempo->stride   = sample_size * channels;
 +
 +    // pick a segment window size:
 +    atempo->window = sample_rate / 24;
 +
 +    // adjust window size to be a power-of-two integer:
 +    nlevels = av_log2(atempo->window);
 +    pot = 1 << nlevels;
 +    av_assert0(pot <= atempo->window);
 +
 +    if (pot < atempo->window) {
 +        atempo->window = pot * 2;
 +        nlevels++;
 +    }
 +
 +    // initialize audio fragment buffers:
 +    REALLOC_OR_FAIL(atempo->frag[0].data, atempo->window * atempo->stride);
 +    REALLOC_OR_FAIL(atempo->frag[1].data, atempo->window * atempo->stride);
 +    REALLOC_OR_FAIL(atempo->frag[0].xdat, atempo->window * sizeof(FFTComplex));
 +    REALLOC_OR_FAIL(atempo->frag[1].xdat, atempo->window * sizeof(FFTComplex));
 +
 +    // initialize rDFT contexts:
 +    av_rdft_end(atempo->real_to_complex);
 +    atempo->real_to_complex = NULL;
 +
 +    av_rdft_end(atempo->complex_to_real);
 +    atempo->complex_to_real = NULL;
 +
 +    atempo->real_to_complex = av_rdft_init(nlevels + 1, DFT_R2C);
 +    if (!atempo->real_to_complex) {
 +        yae_release_buffers(atempo);
 +        return AVERROR(ENOMEM);
 +    }
 +
 +    atempo->complex_to_real = av_rdft_init(nlevels + 1, IDFT_C2R);
 +    if (!atempo->complex_to_real) {
 +        yae_release_buffers(atempo);
 +        return AVERROR(ENOMEM);
 +    }
 +
 +    REALLOC_OR_FAIL(atempo->correlation, atempo->window * sizeof(FFTComplex));
 +
 +    atempo->ring = atempo->window * 3;
 +    REALLOC_OR_FAIL(atempo->buffer, atempo->ring * atempo->stride);
 +
 +    // initialize the Hann window function:
 +    REALLOC_OR_FAIL(atempo->hann, atempo->window * sizeof(float));
 +
 +    for (i = 0; i < atempo->window; i++) {
 +        double t = (double)i / (double)(atempo->window - 1);
 +        double h = 0.5 * (1.0 - cos(2.0 * M_PI * t));
 +        atempo->hann[i] = (float)h;
 +    }
 +
 +    yae_clear(atempo);
 +    return 0;
 +}
 +
 +static int yae_set_tempo(AVFilterContext *ctx, const char *arg_tempo)
 +{
 +    ATempoContext *atempo = ctx->priv;
 +    char   *tail = NULL;
 +    double tempo = av_strtod(arg_tempo, &tail);
 +
 +    if (tail && *tail) {
 +        av_log(ctx, AV_LOG_ERROR, "Invalid tempo value '%s'\n", arg_tempo);
 +        return AVERROR(EINVAL);
 +    }
 +
 +    if (tempo < 0.5 || tempo > 2.0) {
 +        av_log(ctx, AV_LOG_ERROR, "Tempo value %f exceeds [0.5, 2.0] range\n",
 +               tempo);
 +        return AVERROR(EINVAL);
 +    }
 +
 +    atempo->tempo = tempo;
 +    return 0;
 +}
 +
 +inline static AudioFragment *yae_curr_frag(ATempoContext *atempo)
 +{
 +    return &atempo->frag[atempo->nfrag % 2];
 +}
 +
 +inline static AudioFragment *yae_prev_frag(ATempoContext *atempo)
 +{
 +    return &atempo->frag[(atempo->nfrag + 1) % 2];
 +}
 +
 +/**
 + * A helper macro for initializing complex data buffer with scalar data
 + * of a given type.
 + */
 +#define yae_init_xdat(scalar_type, scalar_max)                          \
 +    do {                                                                \
 +        const uint8_t *src_end = src +                                  \
 +            frag->nsamples * atempo->channels * sizeof(scalar_type);    \
 +                                                                        \
 +        FFTSample *xdat = frag->xdat;                                   \
 +        scalar_type tmp;                                                \
 +                                                                        \
 +        if (atempo->channels == 1) {                                    \
 +            for (; src < src_end; xdat++) {                             \
 +                tmp = *(const scalar_type *)src;                        \
 +                src += sizeof(scalar_type);                             \
 +                                                                        \
 +                *xdat = (FFTSample)tmp;                                 \
 +            }                                                           \
 +        } else {                                                        \
 +            FFTSample s, max, ti, si;                                   \
 +            int i;                                                      \
 +                                                                        \
 +            for (; src < src_end; xdat++) {                             \
 +                tmp = *(const scalar_type *)src;                        \
 +                src += sizeof(scalar_type);                             \
 +                                                                        \
 +                max = (FFTSample)tmp;                                   \
 +                s = FFMIN((FFTSample)scalar_max,                        \
 +                          (FFTSample)fabsf(max));                       \
 +                                                                        \
 +                for (i = 1; i < atempo->channels; i++) {                \
 +                    tmp = *(const scalar_type *)src;                    \
 +                    src += sizeof(scalar_type);                         \
 +                                                                        \
 +                    ti = (FFTSample)tmp;                                \
 +                    si = FFMIN((FFTSample)scalar_max,                   \
 +                               (FFTSample)fabsf(ti));                   \
 +                                                                        \
 +                    if (s < si) {                                       \
 +                        s   = si;                                       \
 +                        max = ti;                                       \
 +                    }                                                   \
 +                }                                                       \
 +                                                                        \
 +                *xdat = max;                                            \
 +            }                                                           \
 +        }                                                               \
 +    } while (0)
 +
 +/**
 + * Initialize complex data buffer of a given audio fragment
 + * with down-mixed mono data of appropriate scalar type.
 + */
 +static void yae_downmix(ATempoContext *atempo, AudioFragment *frag)
 +{
 +    // shortcuts:
 +    const uint8_t *src = frag->data;
 +
 +    // init complex data buffer used for FFT and Correlation:
 +    memset(frag->xdat, 0, sizeof(FFTComplex) * atempo->window);
 +
 +    if (atempo->format == AV_SAMPLE_FMT_U8) {
 +        yae_init_xdat(uint8_t, 127);
 +    } else if (atempo->format == AV_SAMPLE_FMT_S16) {
 +        yae_init_xdat(int16_t, 32767);
 +    } else if (atempo->format == AV_SAMPLE_FMT_S32) {
 +        yae_init_xdat(int, 2147483647);
 +    } else if (atempo->format == AV_SAMPLE_FMT_FLT) {
 +        yae_init_xdat(float, 1);
 +    } else if (atempo->format == AV_SAMPLE_FMT_DBL) {
 +        yae_init_xdat(double, 1);
 +    }
 +}
 +
 +/**
 + * Populate the internal data buffer on as-needed basis.
 + *
 + * @return
 + *   0 if requested data was already available or was successfully loaded,
 + *   AVERROR(EAGAIN) if more input data is required.
 + */
 +static int yae_load_data(ATempoContext *atempo,
 +                         const uint8_t **src_ref,
 +                         const uint8_t *src_end,
 +                         int64_t stop_here)
 +{
 +    // shortcut:
 +    const uint8_t *src = *src_ref;
 +    const int read_size = stop_here - atempo->position[0];
 +
 +    if (stop_here <= atempo->position[0]) {
 +        return 0;
 +    }
 +
 +    // samples are not expected to be skipped:
 +    av_assert0(read_size <= atempo->ring);
 +
 +    while (atempo->position[0] < stop_here && src < src_end) {
 +        int src_samples = (src_end - src) / atempo->stride;
 +
 +        // load data piece-wise, in order to avoid complicating the logic:
 +        int nsamples = FFMIN(read_size, src_samples);
 +        int na;
 +        int nb;
 +
 +        nsamples = FFMIN(nsamples, atempo->ring);
 +        na = FFMIN(nsamples, atempo->ring - atempo->tail);
 +        nb = FFMIN(nsamples - na, atempo->ring);
 +
 +        if (na) {
 +            uint8_t *a = atempo->buffer + atempo->tail * atempo->stride;
 +            memcpy(a, src, na * atempo->stride);
 +
 +            src += na * atempo->stride;
 +            atempo->position[0] += na;
 +
 +            atempo->size = FFMIN(atempo->size + na, atempo->ring);
 +            atempo->tail = (atempo->tail + na) % atempo->ring;
 +            atempo->head =
 +                atempo->size < atempo->ring ?
 +                atempo->tail - atempo->size :
 +                atempo->tail;
 +        }
 +
 +        if (nb) {
 +            uint8_t *b = atempo->buffer;
 +            memcpy(b, src, nb * atempo->stride);
 +
 +            src += nb * atempo->stride;
 +            atempo->position[0] += nb;
 +
 +            atempo->size = FFMIN(atempo->size + nb, atempo->ring);
 +            atempo->tail = (atempo->tail + nb) % atempo->ring;
 +            atempo->head =
 +                atempo->size < atempo->ring ?
 +                atempo->tail - atempo->size :
 +                atempo->tail;
 +        }
 +    }
 +
 +    // pass back the updated source buffer pointer:
 +    *src_ref = src;
 +
 +    // sanity check:
 +    av_assert0(atempo->position[0] <= stop_here);
 +
 +    return atempo->position[0] == stop_here ? 0 : AVERROR(EAGAIN);
 +}
 +
 +/**
 + * Populate current audio fragment data buffer.
 + *
 + * @return
 + *   0 when the fragment is ready,
 + *   AVERROR(EAGAIN) if more input data is required.
 + */
 +static int yae_load_frag(ATempoContext *atempo,
 +                         const uint8_t **src_ref,
 +                         const uint8_t *src_end)
 +{
 +    // shortcuts:
 +    AudioFragment *frag = yae_curr_frag(atempo);
 +    uint8_t *dst;
 +    int64_t missing, start, zeros;
 +    uint32_t nsamples;
 +    const uint8_t *a, *b;
 +    int i0, i1, n0, n1, na, nb;
 +
 +    int64_t stop_here = frag->position[0] + atempo->window;
 +    if (src_ref && yae_load_data(atempo, src_ref, src_end, stop_here) != 0) {
 +        return AVERROR(EAGAIN);
 +    }
 +
 +    // calculate the number of samples we don't have:
 +    missing =
 +        stop_here > atempo->position[0] ?
 +        stop_here - atempo->position[0] : 0;
 +
 +    nsamples =
 +        missing < (int64_t)atempo->window ?
 +        (uint32_t)(atempo->window - missing) : 0;
 +
 +    // setup the output buffer:
 +    frag->nsamples = nsamples;
 +    dst = frag->data;
 +
 +    start = atempo->position[0] - atempo->size;
 +    zeros = 0;
 +
 +    if (frag->position[0] < start) {
 +        // what we don't have we substitute with zeros:
 +        zeros = FFMIN(start - frag->position[0], (int64_t)nsamples);
 +        av_assert0(zeros != nsamples);
 +
 +        memset(dst, 0, zeros * atempo->stride);
 +        dst += zeros * atempo->stride;
 +    }
 +
 +    if (zeros == nsamples) {
 +        return 0;
 +    }
 +
 +    // get the remaining data from the ring buffer:
 +    na = (atempo->head < atempo->tail ?
 +          atempo->tail - atempo->head :
 +          atempo->ring - atempo->head);
 +
 +    nb = atempo->head < atempo->tail ? 0 : atempo->tail;
 +
 +    // sanity check:
 +    av_assert0(nsamples <= zeros + na + nb);
 +
 +    a = atempo->buffer + atempo->head * atempo->stride;
 +    b = atempo->buffer;
 +
 +    i0 = frag->position[0] + zeros - start;
 +    i1 = i0 < na ? 0 : i0 - na;
 +
 +    n0 = i0 < na ? FFMIN(na - i0, (int)(nsamples - zeros)) : 0;
 +    n1 = nsamples - zeros - n0;
 +
 +    if (n0) {
 +        memcpy(dst, a + i0 * atempo->stride, n0 * atempo->stride);
 +        dst += n0 * atempo->stride;
 +    }
 +
 +    if (n1) {
 +        memcpy(dst, b + i1 * atempo->stride, n1 * atempo->stride);
 +        dst += n1 * atempo->stride;
 +    }
 +
 +    return 0;
 +}
 +
 +/**
 + * Prepare for loading next audio fragment.
 + */
 +static void yae_advance_to_next_frag(ATempoContext *atempo)
 +{
 +    const double fragment_step = atempo->tempo * (double)(atempo->window / 2);
 +
 +    const AudioFragment *prev;
 +    AudioFragment       *frag;
 +
 +    atempo->nfrag++;
 +    prev = yae_prev_frag(atempo);
 +    frag = yae_curr_frag(atempo);
 +
 +    frag->position[0] = prev->position[0] + (int64_t)fragment_step;
 +    frag->position[1] = prev->position[1] + atempo->window / 2;
 +    frag->nsamples    = 0;
 +}
 +
 +/**
 + * Calculate cross-correlation via rDFT.
 + *
 + * Multiply two vectors of complex numbers (result of real_to_complex rDFT)
 + * and transform back via complex_to_real rDFT.
 + */
 +static void yae_xcorr_via_rdft(FFTSample *xcorr,
 +                               RDFTContext *complex_to_real,
 +                               const FFTComplex *xa,
 +                               const FFTComplex *xb,
 +                               const int window)
 +{
 +    FFTComplex *xc = (FFTComplex *)xcorr;
 +    int i;
 +
 +    // NOTE: first element requires special care -- Given Y = rDFT(X),
 +    // Im(Y[0]) and Im(Y[N/2]) are always zero, therefore av_rdft_calc
 +    // stores Re(Y[N/2]) in place of Im(Y[0]).
 +
 +    xc->re = xa->re * xb->re;
 +    xc->im = xa->im * xb->im;
 +    xa++;
 +    xb++;
 +    xc++;
 +
 +    for (i = 1; i < window; i++, xa++, xb++, xc++) {
 +        xc->re = (xa->re * xb->re + xa->im * xb->im);
 +        xc->im = (xa->im * xb->re - xa->re * xb->im);
 +    }
 +
 +    // apply inverse rDFT:
 +    av_rdft_calc(complex_to_real, xcorr);
 +}
 +
 +/**
 + * Calculate alignment offset for given fragment
 + * relative to the previous fragment.
 + *
 + * @return alignment offset of current fragment relative to previous.
 + */
 +static int yae_align(AudioFragment *frag,
 +                     const AudioFragment *prev,
 +                     const int window,
 +                     const int delta_max,
 +                     const int drift,
 +                     FFTSample *correlation,
 +                     RDFTContext *complex_to_real)
 +{
 +    int       best_offset = -drift;
 +    FFTSample best_metric = -FLT_MAX;
 +    FFTSample *xcorr;
 +
 +    int i0;
 +    int i1;
 +    int i;
 +
 +    yae_xcorr_via_rdft(correlation,
 +                       complex_to_real,
 +                       (const FFTComplex *)prev->xdat,
 +                       (const FFTComplex *)frag->xdat,
 +                       window);
 +
 +    // identify search window boundaries:
 +    i0 = FFMAX(window / 2 - delta_max - drift, 0);
 +    i0 = FFMIN(i0, window);
 +
 +    i1 = FFMIN(window / 2 + delta_max - drift, window - window / 16);
 +    i1 = FFMAX(i1, 0);
 +
 +    // identify cross-correlation peaks within search window:
 +    xcorr = correlation + i0;
 +
 +    for (i = i0; i < i1; i++, xcorr++) {
 +        FFTSample metric = *xcorr;
 +
 +        // normalize:
 +        FFTSample drifti = (FFTSample)(drift + i);
 +        metric *= drifti * (FFTSample)(i - i0) * (FFTSample)(i1 - i);
 +
 +        if (metric > best_metric) {
 +            best_metric = metric;
 +            best_offset = i - window / 2;
 +        }
 +    }
 +
 +    return best_offset;
 +}
 +
 +/**
 + * Adjust current fragment position for better alignment
 + * with previous fragment.
 + *
 + * @return alignment correction.
 + */
 +static int yae_adjust_position(ATempoContext *atempo)
 +{
 +    const AudioFragment *prev = yae_prev_frag(atempo);
 +    AudioFragment       *frag = yae_curr_frag(atempo);
 +
 +    const int delta_max  = atempo->window / 2;
 +    const int correction = yae_align(frag,
 +                                     prev,
 +                                     atempo->window,
 +                                     delta_max,
 +                                     atempo->drift,
 +                                     atempo->correlation,
 +                                     atempo->complex_to_real);
 +
 +    if (correction) {
 +        // adjust fragment position:
 +        frag->position[0] -= correction;
 +
 +        // clear so that the fragment can be reloaded:
 +        frag->nsamples = 0;
 +
 +        // update cumulative correction drift counter:
 +        atempo->drift += correction;
 +    }
 +
 +    return correction;
 +}
 +
 +/**
 + * A helper macro for blending the overlap region of previous
 + * and current audio fragment.
 + */
 +#define yae_blend(scalar_type)                                          \
 +    do {                                                                \
 +        const scalar_type *aaa = (const scalar_type *)a;                \
 +        const scalar_type *bbb = (const scalar_type *)b;                \
 +                                                                        \
 +        scalar_type *out     = (scalar_type *)dst;                      \
 +        scalar_type *out_end = (scalar_type *)dst_end;                  \
 +        int64_t i;                                                      \
 +                                                                        \
 +        for (i = 0; i < overlap && out < out_end;                       \
 +             i++, atempo->position[1]++, wa++, wb++) {                  \
 +            float w0 = *wa;                                             \
 +            float w1 = *wb;                                             \
 +            int j;                                                      \
 +                                                                        \
 +            for (j = 0; j < atempo->channels;                           \
 +                 j++, aaa++, bbb++, out++) {                            \
 +                float t0 = (float)*aaa;                                 \
 +                float t1 = (float)*bbb;                                 \
 +                                                                        \
 +                *out =                                                  \
 +                    frag->position[0] + i < 0 ?                         \
 +                    *aaa :                                              \
 +                    (scalar_type)(t0 * w0 + t1 * w1);                   \
 +            }                                                           \
 +        }                                                               \
 +        dst = (uint8_t *)out;                                           \
 +    } while (0)
 +
 +/**
 + * Blend the overlap region of previous and current audio fragment
 + * and output the results to the given destination buffer.
 + *
 + * @return
 + *   0 if the overlap region was completely stored in the dst buffer,
 + *   AVERROR(EAGAIN) if more destination buffer space is required.
 + */
 +static int yae_overlap_add(ATempoContext *atempo,
 +                           uint8_t **dst_ref,
 +                           uint8_t *dst_end)
 +{
 +    // shortcuts:
 +    const AudioFragment *prev = yae_prev_frag(atempo);
 +    const AudioFragment *frag = yae_curr_frag(atempo);
 +
 +    const int64_t start_here = FFMAX(atempo->position[1],
 +                                     frag->position[1]);
 +
 +    const int64_t stop_here = FFMIN(prev->position[1] + prev->nsamples,
 +                                    frag->position[1] + frag->nsamples);
 +
 +    const int64_t overlap = stop_here - start_here;
 +
 +    const int64_t ia = start_here - prev->position[1];
 +    const int64_t ib = start_here - frag->position[1];
 +
 +    const float *wa = atempo->hann + ia;
 +    const float *wb = atempo->hann + ib;
 +
 +    const uint8_t *a = prev->data + ia * atempo->stride;
 +    const uint8_t *b = frag->data + ib * atempo->stride;
 +
 +    uint8_t *dst = *dst_ref;
 +
 +    av_assert0(start_here <= stop_here &&
 +               frag->position[1] <= start_here &&
 +               overlap <= frag->nsamples);
 +
 +    if (atempo->format == AV_SAMPLE_FMT_U8) {
 +        yae_blend(uint8_t);
 +    } else if (atempo->format == AV_SAMPLE_FMT_S16) {
 +        yae_blend(int16_t);
 +    } else if (atempo->format == AV_SAMPLE_FMT_S32) {
 +        yae_blend(int);
 +    } else if (atempo->format == AV_SAMPLE_FMT_FLT) {
 +        yae_blend(float);
 +    } else if (atempo->format == AV_SAMPLE_FMT_DBL) {
 +        yae_blend(double);
 +    }
 +
 +    // pass-back the updated destination buffer pointer:
 +    *dst_ref = dst;
 +
 +    return atempo->position[1] == stop_here ? 0 : AVERROR(EAGAIN);
 +}
 +
 +/**
 + * Feed as much data to the filter as it is able to consume
 + * and receive as much processed data in the destination buffer
 + * as it is able to produce or store.
 + */
 +static void
 +yae_apply(ATempoContext *atempo,
 +          const uint8_t **src_ref,
 +          const uint8_t *src_end,
 +          uint8_t **dst_ref,
 +          uint8_t *dst_end)
 +{
 +    while (1) {
 +        if (atempo->state == YAE_LOAD_FRAGMENT) {
 +            // load additional data for the current fragment:
 +            if (yae_load_frag(atempo, src_ref, src_end) != 0) {
 +                break;
 +            }
 +
 +            // down-mix to mono:
 +            yae_downmix(atempo, yae_curr_frag(atempo));
 +
 +            // apply rDFT:
 +            av_rdft_calc(atempo->real_to_complex, yae_curr_frag(atempo)->xdat);
 +
 +            // must load the second fragment before alignment can start:
 +            if (!atempo->nfrag) {
 +                yae_advance_to_next_frag(atempo);
 +                continue;
 +            }
 +
 +            atempo->state = YAE_ADJUST_POSITION;
 +        }
 +
 +        if (atempo->state == YAE_ADJUST_POSITION) {
 +            // adjust position for better alignment:
 +            if (yae_adjust_position(atempo)) {
 +                // reload the fragment at the corrected position, so that the
 +                // Hann window blending would not require normalization:
 +                atempo->state = YAE_RELOAD_FRAGMENT;
 +            } else {
 +                atempo->state = YAE_OUTPUT_OVERLAP_ADD;
 +            }
 +        }
 +
 +        if (atempo->state == YAE_RELOAD_FRAGMENT) {
 +            // load additional data if necessary due to position adjustment:
 +            if (yae_load_frag(atempo, src_ref, src_end) != 0) {
 +                break;
 +            }
 +
 +            // down-mix to mono:
 +            yae_downmix(atempo, yae_curr_frag(atempo));
 +
 +            // apply rDFT:
 +            av_rdft_calc(atempo->real_to_complex, yae_curr_frag(atempo)->xdat);
 +
 +            atempo->state = YAE_OUTPUT_OVERLAP_ADD;
 +        }
 +
 +        if (atempo->state == YAE_OUTPUT_OVERLAP_ADD) {
 +            // overlap-add and output the result:
 +            if (yae_overlap_add(atempo, dst_ref, dst_end) != 0) {
 +                break;
 +            }
 +
 +            // advance to the next fragment, repeat:
 +            yae_advance_to_next_frag(atempo);
 +            atempo->state = YAE_LOAD_FRAGMENT;
 +        }
 +    }
 +}
 +
 +/**
 + * Flush any buffered data from the filter.
 + *
 + * @return
 + *   0 if all data was completely stored in the dst buffer,
 + *   AVERROR(EAGAIN) if more destination buffer space is required.
 + */
 +static int yae_flush(ATempoContext *atempo,
 +                     uint8_t **dst_ref,
 +                     uint8_t *dst_end)
 +{
 +    AudioFragment *frag = yae_curr_frag(atempo);
 +    int64_t overlap_end;
 +    int64_t start_here;
 +    int64_t stop_here;
 +    int64_t offset;
 +
 +    const uint8_t *src;
 +    uint8_t *dst;
 +
 +    int src_size;
 +    int dst_size;
 +    int nbytes;
 +
 +    atempo->state = YAE_FLUSH_OUTPUT;
 +
 +    if (atempo->position[0] == frag->position[0] + frag->nsamples &&
 +        atempo->position[1] == frag->position[1] + frag->nsamples) {
 +        // the current fragment is already flushed:
 +        return 0;
 +    }
 +
 +    if (frag->position[0] + frag->nsamples < atempo->position[0]) {
 +        // finish loading the current (possibly partial) fragment:
 +        yae_load_frag(atempo, NULL, NULL);
 +
 +        if (atempo->nfrag) {
 +            // down-mix to mono:
 +            yae_downmix(atempo, frag);
 +
 +            // apply rDFT:
 +            av_rdft_calc(atempo->real_to_complex, frag->xdat);
 +
 +            // align current fragment to previous fragment:
 +            if (yae_adjust_position(atempo)) {
 +                // reload the current fragment due to adjusted position:
 +                yae_load_frag(atempo, NULL, NULL);
 +            }
 +        }
 +    }
 +
 +    // flush the overlap region:
 +    overlap_end = frag->position[1] + FFMIN(atempo->window / 2,
 +                                            frag->nsamples);
 +
 +    while (atempo->position[1] < overlap_end) {
 +        if (yae_overlap_add(atempo, dst_ref, dst_end) != 0) {
 +            return AVERROR(EAGAIN);
 +        }
 +    }
 +
 +    // flush the remaininder of the current fragment:
 +    start_here = FFMAX(atempo->position[1], overlap_end);
 +    stop_here  = frag->position[1] + frag->nsamples;
 +    offset     = start_here - frag->position[1];
 +    av_assert0(start_here <= stop_here && frag->position[1] <= start_here);
 +
 +    src = frag->data + offset * atempo->stride;
 +    dst = (uint8_t *)*dst_ref;
 +
 +    src_size = (int)(stop_here - start_here) * atempo->stride;
 +    dst_size = dst_end - dst;
 +    nbytes = FFMIN(src_size, dst_size);
 +
 +    memcpy(dst, src, nbytes);
 +    dst += nbytes;
 +
 +    atempo->position[1] += (nbytes / atempo->stride);
 +
 +    // pass-back the updated destination buffer pointer:
 +    *dst_ref = (uint8_t *)dst;
 +
 +    return atempo->position[1] == stop_here ? 0 : AVERROR(EAGAIN);
 +}
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args)
 +{
 +    ATempoContext *atempo = ctx->priv;
 +
 +    // NOTE: this assumes that the caller has memset ctx->priv to 0:
 +    atempo->format = AV_SAMPLE_FMT_NONE;
 +    atempo->tempo  = 1.0;
 +    atempo->state  = YAE_LOAD_FRAGMENT;
 +
 +    return args ? yae_set_tempo(ctx, args) : 0;
 +}
 +
 +static av_cold void uninit(AVFilterContext *ctx)
 +{
 +    ATempoContext *atempo = ctx->priv;
 +    yae_release_buffers(atempo);
 +}
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    AVFilterChannelLayouts *layouts = NULL;
 +    AVFilterFormats        *formats = NULL;
 +
 +    // WSOLA necessitates an internal sliding window ring buffer
 +    // for incoming audio stream.
 +    //
 +    // Planar sample formats are too cumbersome to store in a ring buffer,
 +    // therefore planar sample formats are not supported.
 +    //
 +    enum AVSampleFormat sample_fmts[] = {
 +        AV_SAMPLE_FMT_U8,
 +        AV_SAMPLE_FMT_S16,
 +        AV_SAMPLE_FMT_S32,
 +        AV_SAMPLE_FMT_FLT,
 +        AV_SAMPLE_FMT_DBL,
 +        AV_SAMPLE_FMT_NONE
 +    };
 +
 +    layouts = ff_all_channel_layouts();
 +    if (!layouts) {
 +        return AVERROR(ENOMEM);
 +    }
 +    ff_set_common_channel_layouts(ctx, layouts);
 +
 +    formats = ff_make_format_list(sample_fmts);
 +    if (!formats) {
 +        return AVERROR(ENOMEM);
 +    }
 +    ff_set_common_formats(ctx, formats);
 +
 +    formats = ff_all_samplerates();
 +    if (!formats) {
 +        return AVERROR(ENOMEM);
 +    }
 +    ff_set_common_samplerates(ctx, formats);
 +
 +    return 0;
 +}
 +
 +static int config_props(AVFilterLink *inlink)
 +{
 +    AVFilterContext  *ctx = inlink->dst;
 +    ATempoContext *atempo = ctx->priv;
 +
 +    enum AVSampleFormat format = inlink->format;
 +    int sample_rate = (int)inlink->sample_rate;
 +    int channels = av_get_channel_layout_nb_channels(inlink->channel_layout);
 +
 +    return yae_reset(atempo, format, sample_rate, channels);
 +}
 +
 +static void push_samples(ATempoContext *atempo,
 +                         AVFilterLink *outlink,
 +                         int n_out)
 +{
 +    atempo->dst_buffer->audio->sample_rate = outlink->sample_rate;
 +    atempo->dst_buffer->audio->nb_samples  = n_out;
 +
 +    // adjust the PTS:
 +    atempo->dst_buffer->pts =
 +        av_rescale_q(atempo->nsamples_out,
 +                     (AVRational){ 1, outlink->sample_rate },
 +                     outlink->time_base);
 +
 +    ff_filter_samples(outlink, atempo->dst_buffer);
 +    atempo->dst_buffer = NULL;
 +    atempo->dst        = NULL;
 +    atempo->dst_end    = NULL;
 +
 +    atempo->nsamples_out += n_out;
 +}
 +
++static int filter_samples(AVFilterLink *inlink,
 +                           AVFilterBufferRef *src_buffer)
 +{
 +    AVFilterContext  *ctx = inlink->dst;
 +    ATempoContext *atempo = ctx->priv;
 +    AVFilterLink *outlink = ctx->outputs[0];
 +
 +    int n_in = src_buffer->audio->nb_samples;
 +    int n_out = (int)(0.5 + ((double)n_in) / atempo->tempo);
 +
 +    const uint8_t *src = src_buffer->data[0];
 +    const uint8_t *src_end = src + n_in * atempo->stride;
 +
 +    while (src < src_end) {
 +        if (!atempo->dst_buffer) {
 +            atempo->dst_buffer = ff_get_audio_buffer(outlink,
 +                                                     AV_PERM_WRITE,
 +                                                     n_out);
 +            avfilter_copy_buffer_ref_props(atempo->dst_buffer, src_buffer);
 +
 +            atempo->dst = atempo->dst_buffer->data[0];
 +            atempo->dst_end = atempo->dst + n_out * atempo->stride;
 +        }
 +
 +        yae_apply(atempo, &src, src_end, &atempo->dst, atempo->dst_end);
 +
 +        if (atempo->dst == atempo->dst_end) {
 +            push_samples(atempo, outlink, n_out);
 +            atempo->request_fulfilled = 1;
 +        }
 +    }
 +
 +    atempo->nsamples_in += n_in;
 +    avfilter_unref_bufferp(&src_buffer);
++    return 0;
 +}
 +
 +static int request_frame(AVFilterLink *outlink)
 +{
 +    AVFilterContext  *ctx = outlink->src;
 +    ATempoContext *atempo = ctx->priv;
 +    int ret;
 +
 +    atempo->request_fulfilled = 0;
 +    do {
 +        ret = ff_request_frame(ctx->inputs[0]);
 +    }
 +    while (!atempo->request_fulfilled && ret >= 0);
 +
 +    if (ret == AVERROR_EOF) {
 +        // flush the filter:
 +        int n_max = atempo->ring;
 +        int n_out;
 +        int err = AVERROR(EAGAIN);
 +
 +        while (err == AVERROR(EAGAIN)) {
 +            if (!atempo->dst_buffer) {
 +                atempo->dst_buffer = ff_get_audio_buffer(outlink,
 +                                                         AV_PERM_WRITE,
 +                                                         n_max);
 +
 +                atempo->dst = atempo->dst_buffer->data[0];
 +                atempo->dst_end = atempo->dst + n_max * atempo->stride;
 +            }
 +
 +            err = yae_flush(atempo, &atempo->dst, atempo->dst_end);
 +
 +            n_out = ((atempo->dst - atempo->dst_buffer->data[0]) /
 +                     atempo->stride);
 +
 +            if (n_out) {
 +                push_samples(atempo, outlink, n_out);
 +            }
 +        }
 +
 +        avfilter_unref_bufferp(&atempo->dst_buffer);
 +        atempo->dst     = NULL;
 +        atempo->dst_end = NULL;
 +
 +        return AVERROR_EOF;
 +    }
 +
 +    return ret;
 +}
 +
 +static int process_command(AVFilterContext *ctx,
 +                           const char *cmd,
 +                           const char *arg,
 +                           char *res,
 +                           int res_len,
 +                           int flags)
 +{
 +    return !strcmp(cmd, "tempo") ? yae_set_tempo(ctx, arg) : AVERROR(ENOSYS);
 +}
 +
 +AVFilter avfilter_af_atempo = {
 +    .name            = "atempo",
 +    .description     = NULL_IF_CONFIG_SMALL("Adjust audio tempo."),
 +    .init            = init,
 +    .uninit          = uninit,
 +    .query_formats   = query_formats,
 +    .process_command = process_command,
 +    .priv_size       = sizeof(ATempoContext),
 +
 +    .inputs    = (const AVFilterPad[]) {
 +        { .name            = "default",
 +          .type            = AVMEDIA_TYPE_AUDIO,
 +          .filter_samples  = filter_samples,
 +          .config_props    = config_props,
 +          .min_perms       = AV_PERM_READ, },
 +        { .name = NULL}
 +    },
 +
 +    .outputs   = (const AVFilterPad[]) {
 +        { .name            = "default",
 +          .request_frame   = request_frame,
 +          .type            = AVMEDIA_TYPE_AUDIO, },
 +        { .name = NULL}
 +    },
 +};
Simple merge
Simple merge
index d86b410,0000000..7265c43
mode 100644,000000..100644
--- /dev/null
@@@ -1,166 -1,0 +1,169 @@@
- static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +/*
 + * Copyright (c) 2011 Mina Nagy Zaki
 + * Copyright (c) 2000 Edward Beingessner And Sundry Contributors.
 + * This source code is freely redistributable and may be used for any purpose.
 + * This copyright notice must be maintained.  Edward Beingessner And Sundry
 + * Contributors are not responsible for the consequences of using this
 + * software.
 + *
 + * 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
 + * Stereo Widening Effect. Adds audio cues to move stereo image in
 + * front of the listener. Adapted from the libsox earwax effect.
 + */
 +
 +#include "libavutil/audioconvert.h"
 +#include "avfilter.h"
 +#include "audio.h"
 +#include "formats.h"
 +
 +#define NUMTAPS 64
 +
 +static const int8_t filt[NUMTAPS] = {
 +/* 30°  330° */
 +    4,   -6,     /* 32 tap stereo FIR filter. */
 +    4,  -11,     /* One side filters as if the */
 +   -1,   -5,     /* signal was from 30 degrees */
 +    3,    3,     /* from the ear, the other as */
 +   -2,    5,     /* if 330 degrees. */
 +   -5,    0,
 +    9,    1,
 +    6,    3,     /*                         Input                         */
 +   -4,   -1,     /*                   Left         Right                  */
 +   -5,   -3,     /*                __________   __________                */
 +   -2,   -5,     /*               |          | |          |               */
 +   -7,    1,     /*           .---|  Hh,0(f) | |  Hh,0(f) |---.           */
 +    6,   -7,     /*          /    |__________| |__________|    \          */
 +   30,  -29,     /*         /                \ /                \         */
 +   12,   -3,     /*        /                  X                  \        */
 +  -11,    4,     /*       /                  / \                  \       */
 +   -3,    7,     /*  ____V_____   __________V   V__________   _____V____  */
 +  -20,   23,     /* |          | |          |   |          | |          | */
 +    2,    0,     /* | Hh,30(f) | | Hh,330(f)|   | Hh,330(f)| | Hh,30(f) | */
 +    1,   -6,     /* |__________| |__________|   |__________| |__________| */
 +  -14,   -5,     /*      \     ___      /           \      ___     /      */
 +   15,  -18,     /*       \   /   \    /    _____    \    /   \   /       */
 +    6,    7,     /*        `->| + |<--'    /     \    `-->| + |<-'        */
 +   15,  -10,     /*           \___/      _/       \_      \___/           */
 +  -14,   22,     /*               \     / \       / \     /               */
 +   -7,   -2,     /*                `--->| |       | |<---'                */
 +   -4,    9,     /*                     \_/       \_/                     */
 +    6,  -12,     /*                                                       */
 +    6,   -6,     /*                       Headphones                      */
 +    0,  -11,
 +    0,   -5,
 +    4,    0};
 +
 +typedef struct {
 +    int16_t taps[NUMTAPS * 2];
 +} EarwaxContext;
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    int sample_rates[] = { 44100, -1 };
 +
 +    AVFilterFormats *formats = NULL;
 +    AVFilterChannelLayouts *layout = NULL;
 +
 +    ff_add_format(&formats, AV_SAMPLE_FMT_S16);
 +    ff_set_common_formats(ctx, formats);
 +    ff_add_channel_layout(&layout, AV_CH_LAYOUT_STEREO);
 +    ff_set_common_channel_layouts(ctx, layout);
 +    ff_set_common_samplerates(ctx, ff_make_format_list(sample_rates));
 +
 +    return 0;
 +}
 +
 +static int config_input(AVFilterLink *inlink)
 +{
 +    if (inlink->sample_rate != 44100) {
 +        av_log(inlink->dst, AV_LOG_ERROR,
 +               "The earwax filter only works for 44.1kHz audio. Insert "
 +               "a resample filter before this\n");
 +        return AVERROR(EINVAL);
 +    }
 +    return 0;
 +}
 +
 +//FIXME: replace with DSPContext.scalarproduct_int16
 +static inline int16_t *scalarproduct(const int16_t *in, const int16_t *endin, int16_t *out)
 +{
 +    int32_t sample;
 +    int16_t j;
 +
 +    while (in < endin) {
 +        sample = 32;
 +        for (j = 0; j < NUMTAPS; j++)
 +            sample += in[j] * filt[j];
 +        *out = sample >> 6;
 +        out++;
 +        in++;
 +    }
 +
 +    return out;
 +}
 +
-     ff_filter_samples(outlink, outsamples);
++static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +{
 +    AVFilterLink *outlink = inlink->dst->outputs[0];
 +    int16_t *taps, *endin, *in, *out;
 +    AVFilterBufferRef *outsamples =
 +        ff_get_audio_buffer(inlink, AV_PERM_WRITE,
 +                                  insamples->audio->nb_samples);
++    int ret;
++
 +    avfilter_copy_buffer_ref_props(outsamples, insamples);
 +
 +    taps  = ((EarwaxContext *)inlink->dst->priv)->taps;
 +    out   = (int16_t *)outsamples->data[0];
 +    in    = (int16_t *)insamples ->data[0];
 +
 +    // copy part of new input and process with saved input
 +    memcpy(taps+NUMTAPS, in, NUMTAPS * sizeof(*taps));
 +    out   = scalarproduct(taps, taps + NUMTAPS, out);
 +
 +    // process current input
 +    endin = in + insamples->audio->nb_samples * 2 - NUMTAPS;
 +    out   = scalarproduct(in, endin, out);
 +
 +    // save part of input for next round
 +    memcpy(taps, endin, NUMTAPS * sizeof(*taps));
 +
++    ret = ff_filter_samples(outlink, outsamples);
 +    avfilter_unref_buffer(insamples);
++    return ret;
 +}
 +
 +AVFilter avfilter_af_earwax = {
 +    .name           = "earwax",
 +    .description    = NULL_IF_CONFIG_SMALL("Widen the stereo image."),
 +    .query_formats  = query_formats,
 +    .priv_size      = sizeof(EarwaxContext),
 +    .inputs  = (const AVFilterPad[])  {{  .name     = "default",
 +                                    .type           = AVMEDIA_TYPE_AUDIO,
 +                                    .filter_samples = filter_samples,
 +                                    .config_props   = config_input,
 +                                    .min_perms      = AV_PERM_READ, },
 +                                 {  .name = NULL}},
 +
 +    .outputs = (const AVFilterPad[])  {{  .name     = "default",
 +                                    .type           = AVMEDIA_TYPE_AUDIO, },
 +                                 {  .name = NULL}},
 +};
index f451e00,0000000..bb96ad0
mode 100644,000000..100644
--- /dev/null
@@@ -1,388 -1,0 +1,390 @@@
- static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +/*
 + * Copyright (c) 2002 Anders Johansson <ajh@atri.curtin.edu.au>
 + * Copyright (c) 2011 Clément Bœsch <ubitux@gmail.com>
 + * Copyright (c) 2011 Nicolas George <nicolas.george@normalesup.org>
 + *
 + * 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 <stdio.h>
 +#include "libavutil/audioconvert.h"
 +#include "libavutil/avstring.h"
 +#include "libavutil/opt.h"
 +#include "libswresample/swresample.h"
 +#include "audio.h"
 +#include "avfilter.h"
 +#include "formats.h"
 +#include "internal.h"
 +
 +#define MAX_CHANNELS 63
 +
 +typedef struct PanContext {
 +    int64_t out_channel_layout;
 +    double gain[MAX_CHANNELS][MAX_CHANNELS];
 +    int64_t need_renorm;
 +    int need_renumber;
 +    int nb_input_channels;
 +    int nb_output_channels;
 +
 +    int pure_gains;
 +    /* channel mapping specific */
 +    int channel_map[SWR_CH_MAX];
 +    struct SwrContext *swr;
 +} PanContext;
 +
 +static int parse_channel_name(char **arg, int *rchannel, int *rnamed)
 +{
 +    char buf[8];
 +    int len, i, channel_id = 0;
 +    int64_t layout, layout0;
 +
 +    /* try to parse a channel name, e.g. "FL" */
 +    if (sscanf(*arg, " %7[A-Z] %n", buf, &len)) {
 +        layout0 = layout = av_get_channel_layout(buf);
 +        /* channel_id <- first set bit in layout */
 +        for (i = 32; i > 0; i >>= 1) {
 +            if (layout >= (int64_t)1 << i) {
 +                channel_id += i;
 +                layout >>= i;
 +            }
 +        }
 +        /* reject layouts that are not a single channel */
 +        if (channel_id >= MAX_CHANNELS || layout0 != (int64_t)1 << channel_id)
 +            return AVERROR(EINVAL);
 +        *rchannel = channel_id;
 +        *rnamed = 1;
 +        *arg += len;
 +        return 0;
 +    }
 +    /* try to parse a channel number, e.g. "c2" */
 +    if (sscanf(*arg, " c%d %n", &channel_id, &len) &&
 +        channel_id >= 0 && channel_id < MAX_CHANNELS) {
 +        *rchannel = channel_id;
 +        *rnamed = 0;
 +        *arg += len;
 +        return 0;
 +    }
 +    return AVERROR(EINVAL);
 +}
 +
 +static void skip_spaces(char **arg)
 +{
 +    int len = 0;
 +
 +    sscanf(*arg, " %n", &len);
 +    *arg += len;
 +}
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args0)
 +{
 +    PanContext *const pan = ctx->priv;
 +    char *arg, *arg0, *tokenizer, *args = av_strdup(args0);
 +    int out_ch_id, in_ch_id, len, named, ret;
 +    int nb_in_channels[2] = { 0, 0 }; // number of unnamed and named input channels
 +    double gain;
 +
 +    if (!args0) {
 +        av_log(ctx, AV_LOG_ERROR,
 +               "pan filter needs a channel layout and a set "
 +               "of channels definitions as parameter\n");
 +        return AVERROR(EINVAL);
 +    }
 +    if (!args)
 +        return AVERROR(ENOMEM);
 +    arg = av_strtok(args, ":", &tokenizer);
 +    ret = ff_parse_channel_layout(&pan->out_channel_layout, arg, ctx);
 +    if (ret < 0)
 +        return ret;
 +    pan->nb_output_channels = av_get_channel_layout_nb_channels(pan->out_channel_layout);
 +
 +    /* parse channel specifications */
 +    while ((arg = arg0 = av_strtok(NULL, ":", &tokenizer))) {
 +        /* channel name */
 +        if (parse_channel_name(&arg, &out_ch_id, &named)) {
 +            av_log(ctx, AV_LOG_ERROR,
 +                   "Expected out channel name, got \"%.8s\"\n", arg);
 +            return AVERROR(EINVAL);
 +        }
 +        if (named) {
 +            if (!((pan->out_channel_layout >> out_ch_id) & 1)) {
 +                av_log(ctx, AV_LOG_ERROR,
 +                       "Channel \"%.8s\" does not exist in the chosen layout\n", arg0);
 +                return AVERROR(EINVAL);
 +            }
 +            /* get the channel number in the output channel layout:
 +             * out_channel_layout & ((1 << out_ch_id) - 1) are all the
 +             * channels that come before out_ch_id,
 +             * so their count is the index of out_ch_id */
 +            out_ch_id = av_get_channel_layout_nb_channels(pan->out_channel_layout & (((int64_t)1 << out_ch_id) - 1));
 +        }
 +        if (out_ch_id < 0 || out_ch_id >= pan->nb_output_channels) {
 +            av_log(ctx, AV_LOG_ERROR,
 +                   "Invalid out channel name \"%.8s\"\n", arg0);
 +            return AVERROR(EINVAL);
 +        }
 +        if (*arg == '=') {
 +            arg++;
 +        } else if (*arg == '<') {
 +            pan->need_renorm |= (int64_t)1 << out_ch_id;
 +            arg++;
 +        } else {
 +            av_log(ctx, AV_LOG_ERROR,
 +                   "Syntax error after channel name in \"%.8s\"\n", arg0);
 +            return AVERROR(EINVAL);
 +        }
 +        /* gains */
 +        while (1) {
 +            gain = 1;
 +            if (sscanf(arg, " %lf %n* %n", &gain, &len, &len))
 +                arg += len;
 +            if (parse_channel_name(&arg, &in_ch_id, &named)){
 +                av_log(ctx, AV_LOG_ERROR,
 +                       "Expected in channel name, got \"%.8s\"\n", arg);
 +                return AVERROR(EINVAL);
 +            }
 +            nb_in_channels[named]++;
 +            if (nb_in_channels[!named]) {
 +                av_log(ctx, AV_LOG_ERROR,
 +                       "Can not mix named and numbered channels\n");
 +                return AVERROR(EINVAL);
 +            }
 +            pan->gain[out_ch_id][in_ch_id] = gain;
 +            if (!*arg)
 +                break;
 +            if (*arg != '+') {
 +                av_log(ctx, AV_LOG_ERROR, "Syntax error near \"%.8s\"\n", arg);
 +                return AVERROR(EINVAL);
 +            }
 +            arg++;
 +            skip_spaces(&arg);
 +        }
 +    }
 +    pan->need_renumber = !!nb_in_channels[1];
 +
 +    av_free(args);
 +    return 0;
 +}
 +
 +static int are_gains_pure(const PanContext *pan)
 +{
 +    int i, j;
 +
 +    for (i = 0; i < MAX_CHANNELS; i++) {
 +        int nb_gain = 0;
 +
 +        for (j = 0; j < MAX_CHANNELS; j++) {
 +            double gain = pan->gain[i][j];
 +
 +            /* channel mapping is effective only if 0% or 100% of a channel is
 +             * selected... */
 +            if (gain != 0. && gain != 1.)
 +                return 0;
 +            /* ...and if the output channel is only composed of one input */
 +            if (gain && nb_gain++)
 +                return 0;
 +        }
 +    }
 +    return 1;
 +}
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    PanContext *pan = ctx->priv;
 +    AVFilterLink *inlink  = ctx->inputs[0];
 +    AVFilterLink *outlink = ctx->outputs[0];
 +    AVFilterFormats *formats = NULL;
 +    AVFilterChannelLayouts *layouts;
 +
 +    pan->pure_gains = are_gains_pure(pan);
 +    /* libswr supports any sample and packing formats */
 +    ff_set_common_formats(ctx, ff_all_formats(AVMEDIA_TYPE_AUDIO));
 +
 +    formats = ff_all_samplerates();
 +    if (!formats)
 +        return AVERROR(ENOMEM);
 +    ff_set_common_samplerates(ctx, formats);
 +
 +    // inlink supports any channel layout
 +    layouts = ff_all_channel_layouts();
 +    ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts);
 +
 +    // outlink supports only requested output channel layout
 +    layouts = NULL;
 +    ff_add_channel_layout(&layouts, pan->out_channel_layout);
 +    ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts);
 +    return 0;
 +}
 +
 +static int config_props(AVFilterLink *link)
 +{
 +    AVFilterContext *ctx = link->dst;
 +    PanContext *pan = ctx->priv;
 +    char buf[1024], *cur;
 +    int i, j, k, r;
 +    double t;
 +
 +    pan->nb_input_channels = av_get_channel_layout_nb_channels(link->channel_layout);
 +    if (pan->need_renumber) {
 +        // input channels were given by their name: renumber them
 +        for (i = j = 0; i < MAX_CHANNELS; i++) {
 +            if ((link->channel_layout >> i) & 1) {
 +                for (k = 0; k < pan->nb_output_channels; k++)
 +                    pan->gain[k][j] = pan->gain[k][i];
 +                j++;
 +            }
 +        }
 +    }
 +
 +    // sanity check; can't be done in query_formats since the inlink
 +    // channel layout is unknown at that time
 +    if (pan->nb_input_channels > SWR_CH_MAX ||
 +        pan->nb_output_channels > SWR_CH_MAX) {
 +        av_log(ctx, AV_LOG_ERROR,
 +               "libswresample support a maximum of %d channels. "
 +               "Feel free to ask for a higher limit.\n", SWR_CH_MAX);
 +        return AVERROR_PATCHWELCOME;
 +    }
 +
 +    // init libswresample context
 +    pan->swr = swr_alloc_set_opts(pan->swr,
 +                                  pan->out_channel_layout, link->format, link->sample_rate,
 +                                  link->channel_layout,    link->format, link->sample_rate,
 +                                  0, ctx);
 +    if (!pan->swr)
 +        return AVERROR(ENOMEM);
 +
 +    // gains are pure, init the channel mapping
 +    if (pan->pure_gains) {
 +
 +        // get channel map from the pure gains
 +        for (i = 0; i < pan->nb_output_channels; i++) {
 +            int ch_id = -1;
 +            for (j = 0; j < pan->nb_input_channels; j++) {
 +                if (pan->gain[i][j]) {
 +                    ch_id = j;
 +                    break;
 +                }
 +            }
 +            pan->channel_map[i] = ch_id;
 +        }
 +
 +        av_opt_set_int(pan->swr, "icl", pan->out_channel_layout, 0);
 +        av_opt_set_int(pan->swr, "uch", pan->nb_output_channels, 0);
 +        swr_set_channel_mapping(pan->swr, pan->channel_map);
 +    } else {
 +        // renormalize
 +        for (i = 0; i < pan->nb_output_channels; i++) {
 +            if (!((pan->need_renorm >> i) & 1))
 +                continue;
 +            t = 0;
 +            for (j = 0; j < pan->nb_input_channels; j++)
 +                t += pan->gain[i][j];
 +            if (t > -1E-5 && t < 1E-5) {
 +                // t is almost 0 but not exactly, this is probably a mistake
 +                if (t)
 +                    av_log(ctx, AV_LOG_WARNING,
 +                           "Degenerate coefficients while renormalizing\n");
 +                continue;
 +            }
 +            for (j = 0; j < pan->nb_input_channels; j++)
 +                pan->gain[i][j] /= t;
 +        }
 +        av_opt_set_int(pan->swr, "icl", link->channel_layout, 0);
 +        av_opt_set_int(pan->swr, "ocl", pan->out_channel_layout, 0);
 +        swr_set_matrix(pan->swr, pan->gain[0], pan->gain[1] - pan->gain[0]);
 +    }
 +
 +    r = swr_init(pan->swr);
 +    if (r < 0)
 +        return r;
 +
 +    // summary
 +    for (i = 0; i < pan->nb_output_channels; i++) {
 +        cur = buf;
 +        for (j = 0; j < pan->nb_input_channels; j++) {
 +            r = snprintf(cur, buf + sizeof(buf) - cur, "%s%.3g i%d",
 +                         j ? " + " : "", pan->gain[i][j], j);
 +            cur += FFMIN(buf + sizeof(buf) - cur, r);
 +        }
 +        av_log(ctx, AV_LOG_INFO, "o%d = %s\n", i, buf);
 +    }
 +    // add channel mapping summary if possible
 +    if (pan->pure_gains) {
 +        av_log(ctx, AV_LOG_INFO, "Pure channel mapping detected:");
 +        for (i = 0; i < pan->nb_output_channels; i++)
 +            if (pan->channel_map[i] < 0)
 +                av_log(ctx, AV_LOG_INFO, " M");
 +            else
 +                av_log(ctx, AV_LOG_INFO, " %d", pan->channel_map[i]);
 +        av_log(ctx, AV_LOG_INFO, "\n");
 +        return 0;
 +    }
 +    return 0;
 +}
 +
-     ff_filter_samples(outlink, outsamples);
++static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +{
++    int ret;
 +    int n = insamples->audio->nb_samples;
 +    AVFilterLink *const outlink = inlink->dst->outputs[0];
 +    AVFilterBufferRef *outsamples = ff_get_audio_buffer(outlink, AV_PERM_WRITE, n);
 +    PanContext *pan = inlink->dst->priv;
 +
 +    swr_convert(pan->swr, outsamples->data, n, (void *)insamples->data, n);
 +    avfilter_copy_buffer_ref_props(outsamples, insamples);
 +    outsamples->audio->channel_layout = outlink->channel_layout;
 +
++    ret = ff_filter_samples(outlink, outsamples);
 +    avfilter_unref_buffer(insamples);
++    return ret;
 +}
 +
 +static av_cold void uninit(AVFilterContext *ctx)
 +{
 +    PanContext *pan = ctx->priv;
 +    swr_free(&pan->swr);
 +}
 +
 +AVFilter avfilter_af_pan = {
 +    .name          = "pan",
 +    .description   = NULL_IF_CONFIG_SMALL("Remix channels with coefficients (panning)."),
 +    .priv_size     = sizeof(PanContext),
 +    .init          = init,
 +    .uninit        = uninit,
 +    .query_formats = query_formats,
 +
 +    .inputs    = (const AVFilterPad[]) {
 +        { .name             = "default",
 +          .type             = AVMEDIA_TYPE_AUDIO,
 +          .config_props     = config_props,
 +          .filter_samples   = filter_samples,
 +          .min_perms        = AV_PERM_READ, },
 +        { .name = NULL}
 +    },
 +    .outputs   = (const AVFilterPad[]) {
 +        { .name             = "default",
 +          .type             = AVMEDIA_TYPE_AUDIO, },
 +        { .name = NULL}
 +    },
 +};
index 724a923,0000000..d3b125f
mode 100644,000000..100644
--- /dev/null
@@@ -1,170 -1,0 +1,170 @@@
- static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +/*
 + * Copyright (c) 2012 Clément Bœsch <ubitux@gmail.com>
 + *
 + * 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
 + * Audio silence detector
 + */
 +
 +#include "libavutil/audioconvert.h"
 +#include "libavutil/opt.h"
 +#include "libavutil/timestamp.h"
 +#include "audio.h"
 +#include "formats.h"
 +#include "avfilter.h"
 +#include "internal.h"
 +
 +typedef struct {
 +    const AVClass *class;
 +    char *noise_str;            ///< noise option string
 +    double noise;               ///< noise amplitude ratio
 +    int duration;               ///< minimum duration of silence until notification
 +    int64_t nb_null_samples;    ///< current number of continuous zero samples
 +    int64_t start;              ///< if silence is detected, this value contains the time of the first zero sample
 +    int last_sample_rate;       ///< last sample rate to check for sample rate changes
 +} SilenceDetectContext;
 +
 +#define OFFSET(x) offsetof(SilenceDetectContext, x)
 +static const AVOption silencedetect_options[] = {
 +    { "n",         "set noise tolerance",              OFFSET(noise_str), AV_OPT_TYPE_STRING, {.str="-60dB"}, CHAR_MIN, CHAR_MAX },
 +    { "noise",     "set noise tolerance",              OFFSET(noise_str), AV_OPT_TYPE_STRING, {.str="-60dB"}, CHAR_MIN, CHAR_MAX },
 +    { "d",         "set minimum duration in seconds",  OFFSET(duration),  AV_OPT_TYPE_INT,    {.dbl=2},    0, INT_MAX},
 +    { "duration",  "set minimum duration in seconds",  OFFSET(duration),  AV_OPT_TYPE_INT,    {.dbl=2},    0, INT_MAX},
 +    { NULL },
 +};
 +
 +AVFILTER_DEFINE_CLASS(silencedetect);
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args)
 +{
 +    int ret;
 +    char *tail;
 +    SilenceDetectContext *silence = ctx->priv;
 +
 +    silence->class = &silencedetect_class;
 +    av_opt_set_defaults(silence);
 +
 +    if ((ret = av_set_options_string(silence, args, "=", ":")) < 0) {
 +        av_log(ctx, AV_LOG_ERROR, "Error parsing options string: '%s'\n", args);
 +        return ret;
 +    }
 +
 +    silence->noise = strtod(silence->noise_str, &tail);
 +    if (!strcmp(tail, "dB")) {
 +        silence->noise = pow(10, silence->noise/20);
 +    } else if (*tail) {
 +        av_log(ctx, AV_LOG_ERROR, "Invalid value '%s' for noise parameter.\n",
 +               silence->noise_str);
 +        return AVERROR(EINVAL);
 +    }
 +
 +    return 0;
 +}
 +
-     ff_filter_samples(inlink->dst->outputs[0], insamples);
++static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +{
 +    int i;
 +    SilenceDetectContext *silence = inlink->dst->priv;
 +    const int nb_channels           = av_get_channel_layout_nb_channels(inlink->channel_layout);
 +    const int srate                 = inlink->sample_rate;
 +    const int nb_samples            = insamples->audio->nb_samples * nb_channels;
 +    const int64_t nb_samples_notify = srate * silence->duration    * nb_channels;
 +
 +    // scale number of null samples to the new sample rate
 +    if (silence->last_sample_rate && silence->last_sample_rate != srate)
 +        silence->nb_null_samples =
 +            srate * silence->nb_null_samples / silence->last_sample_rate;
 +    silence->last_sample_rate = srate;
 +
 +    // TODO: support more sample formats
 +    if (insamples->format == AV_SAMPLE_FMT_DBL) {
 +        double *p = (double *)insamples->data[0];
 +
 +        for (i = 0; i < nb_samples; i++, p++) {
 +            if (*p < silence->noise && *p > -silence->noise) {
 +                if (!silence->start) {
 +                    silence->nb_null_samples++;
 +                    if (silence->nb_null_samples >= nb_samples_notify) {
 +                        silence->start = insamples->pts - silence->duration / av_q2d(inlink->time_base);
 +                        av_log(silence, AV_LOG_INFO,
 +                               "silence_start: %s\n", av_ts2timestr(silence->start, &inlink->time_base));
 +                    }
 +                }
 +            } else {
 +                if (silence->start)
 +                    av_log(silence, AV_LOG_INFO,
 +                           "silence_end: %s | silence_duration: %s\n",
 +                           av_ts2timestr(insamples->pts,                  &inlink->time_base),
 +                           av_ts2timestr(insamples->pts - silence->start, &inlink->time_base));
 +                silence->nb_null_samples = silence->start = 0;
 +            }
 +        }
 +    }
 +
++    return ff_filter_samples(inlink->dst->outputs[0], insamples);
 +}
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    AVFilterFormats *formats = NULL;
 +    AVFilterChannelLayouts *layouts = NULL;
 +    enum AVSampleFormat sample_fmts[] = {
 +        AV_SAMPLE_FMT_DBL,
 +        AV_SAMPLE_FMT_NONE
 +    };
 +
 +    layouts = ff_all_channel_layouts();
 +    if (!layouts)
 +        return AVERROR(ENOMEM);
 +    ff_set_common_channel_layouts(ctx, layouts);
 +
 +    formats = ff_make_format_list(sample_fmts);
 +    if (!formats)
 +        return AVERROR(ENOMEM);
 +    ff_set_common_formats(ctx, formats);
 +
 +    formats = ff_all_samplerates();
 +    if (!formats)
 +        return AVERROR(ENOMEM);
 +    ff_set_common_samplerates(ctx, formats);
 +
 +    return 0;
 +}
 +
 +AVFilter avfilter_af_silencedetect = {
 +    .name          = "silencedetect",
 +    .description   = NULL_IF_CONFIG_SMALL("Detect silence."),
 +    .priv_size     = sizeof(SilenceDetectContext),
 +    .init          = init,
 +    .query_formats = query_formats,
 +
 +    .inputs = (const AVFilterPad[]) {
 +        { .name             = "default",
 +          .type             = AVMEDIA_TYPE_AUDIO,
 +          .get_audio_buffer = ff_null_get_audio_buffer,
 +          .filter_samples   = filter_samples, },
 +        { .name = NULL }
 +    },
 +    .outputs = (const AVFilterPad[]) {
 +        { .name = "default",
 +          .type = AVMEDIA_TYPE_AUDIO, },
 +        { .name = NULL }
 +    },
 +};
index 11da226,0000000..09302ee
mode 100644,000000..100644
--- /dev/null
@@@ -1,191 -1,0 +1,191 @@@
- static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +/*
 + * Copyright (c) 2011 Stefano Sabatini
 + *
 + * 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
 + * audio volume filter
 + * based on ffmpeg.c code
 + */
 +
 +#include "libavutil/audioconvert.h"
 +#include "libavutil/eval.h"
 +#include "audio.h"
 +#include "avfilter.h"
 +#include "formats.h"
 +
 +typedef struct {
 +    double volume;
 +    int    volume_i;
 +} VolumeContext;
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args)
 +{
 +    VolumeContext *vol = ctx->priv;
 +    char *tail;
 +    int ret = 0;
 +
 +    vol->volume = 1.0;
 +
 +    if (args) {
 +        /* parse the number as a decimal number */
 +        double d = strtod(args, &tail);
 +
 +        if (*tail) {
 +            if (!strcmp(tail, "dB")) {
 +                /* consider the argument an adjustement in decibels */
 +                d = pow(10, d/20);
 +            } else {
 +                /* parse the argument as an expression */
 +                ret = av_expr_parse_and_eval(&d, args, NULL, NULL,
 +                                             NULL, NULL, NULL, NULL,
 +                                             NULL, 0, ctx);
 +            }
 +        }
 +
 +        if (ret < 0) {
 +            av_log(ctx, AV_LOG_ERROR,
 +                   "Invalid volume argument '%s'\n", args);
 +            return AVERROR(EINVAL);
 +        }
 +
 +        if (d < 0 || d > 65536) { /* 65536 = INT_MIN / (128 * 256) */
 +            av_log(ctx, AV_LOG_ERROR,
 +                   "Negative or too big volume value %f\n", d);
 +            return AVERROR(EINVAL);
 +        }
 +
 +        vol->volume = d;
 +    }
 +
 +    vol->volume_i = (int)(vol->volume * 256 + 0.5);
 +    av_log(ctx, AV_LOG_INFO, "volume=%f\n", vol->volume);
 +    return 0;
 +}
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    AVFilterFormats *formats = NULL;
 +    AVFilterChannelLayouts *layouts;
 +    enum AVSampleFormat sample_fmts[] = {
 +        AV_SAMPLE_FMT_U8,
 +        AV_SAMPLE_FMT_S16,
 +        AV_SAMPLE_FMT_S32,
 +        AV_SAMPLE_FMT_FLT,
 +        AV_SAMPLE_FMT_DBL,
 +        AV_SAMPLE_FMT_NONE
 +    };
 +
 +    layouts = ff_all_channel_layouts();
 +    if (!layouts)
 +        return AVERROR(ENOMEM);
 +    ff_set_common_channel_layouts(ctx, layouts);
 +
 +    formats = ff_make_format_list(sample_fmts);
 +    if (!formats)
 +        return AVERROR(ENOMEM);
 +    ff_set_common_formats(ctx, formats);
 +
 +    formats = ff_all_samplerates();
 +    if (!formats)
 +        return AVERROR(ENOMEM);
 +    ff_set_common_samplerates(ctx, formats);
 +
 +    return 0;
 +}
 +
-     ff_filter_samples(outlink, insamples);
++static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +{
 +    VolumeContext *vol = inlink->dst->priv;
 +    AVFilterLink *outlink = inlink->dst->outputs[0];
 +    const int nb_samples = insamples->audio->nb_samples *
 +        av_get_channel_layout_nb_channels(insamples->audio->channel_layout);
 +    const double volume   = vol->volume;
 +    const int    volume_i = vol->volume_i;
 +    int i;
 +
 +    if (volume_i != 256) {
 +        switch (insamples->format) {
 +        case AV_SAMPLE_FMT_U8:
 +        {
 +            uint8_t *p = (void *)insamples->data[0];
 +            for (i = 0; i < nb_samples; i++) {
 +                int v = (((*p - 128) * volume_i + 128) >> 8) + 128;
 +                *p++ = av_clip_uint8(v);
 +            }
 +            break;
 +        }
 +        case AV_SAMPLE_FMT_S16:
 +        {
 +            int16_t *p = (void *)insamples->data[0];
 +            for (i = 0; i < nb_samples; i++) {
 +                int v = ((int64_t)*p * volume_i + 128) >> 8;
 +                *p++ = av_clip_int16(v);
 +            }
 +            break;
 +        }
 +        case AV_SAMPLE_FMT_S32:
 +        {
 +            int32_t *p = (void *)insamples->data[0];
 +            for (i = 0; i < nb_samples; i++) {
 +                int64_t v = (((int64_t)*p * volume_i + 128) >> 8);
 +                *p++ = av_clipl_int32(v);
 +            }
 +            break;
 +        }
 +        case AV_SAMPLE_FMT_FLT:
 +        {
 +            float *p = (void *)insamples->data[0];
 +            float scale = (float)volume;
 +            for (i = 0; i < nb_samples; i++) {
 +                *p++ *= scale;
 +            }
 +            break;
 +        }
 +        case AV_SAMPLE_FMT_DBL:
 +        {
 +            double *p = (void *)insamples->data[0];
 +            for (i = 0; i < nb_samples; i++) {
 +                *p *= volume;
 +                p++;
 +            }
 +            break;
 +        }
 +        }
 +    }
++    return ff_filter_samples(outlink, insamples);
 +}
 +
 +AVFilter avfilter_af_volume = {
 +    .name           = "volume",
 +    .description    = NULL_IF_CONFIG_SMALL("Change input volume."),
 +    .query_formats  = query_formats,
 +    .priv_size      = sizeof(VolumeContext),
 +    .init           = init,
 +
 +    .inputs  = (const AVFilterPad[])  {{ .name     = "default",
 +                                   .type           = AVMEDIA_TYPE_AUDIO,
 +                                   .filter_samples = filter_samples,
 +                                   .min_perms      = AV_PERM_READ|AV_PERM_WRITE},
 +                                 { .name = NULL}},
 +
 +    .outputs = (const AVFilterPad[])  {{ .name     = "default",
 +                                   .type           = AVMEDIA_TYPE_AUDIO, },
 +                                 { .name = NULL}},
 +};
Simple merge
@@@ -150,21 -146,19 +150,21 @@@ fail
      return NULL;
  }
  
- static void default_filter_samples(AVFilterLink *link,
-                                    AVFilterBufferRef *samplesref)
+ static int default_filter_samples(AVFilterLink *link,
+                                   AVFilterBufferRef *samplesref)
  {
-     ff_filter_samples(link->dst->outputs[0], samplesref);
+     return ff_filter_samples(link->dst->outputs[0], samplesref);
  }
  
- void ff_filter_samples_framed(AVFilterLink *link,
-                               AVFilterBufferRef *samplesref)
 -int ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
++int ff_filter_samples_framed(AVFilterLink *link, AVFilterBufferRef *samplesref)
  {
-     void (*filter_samples)(AVFilterLink *, AVFilterBufferRef *);
+     int (*filter_samples)(AVFilterLink *, AVFilterBufferRef *);
      AVFilterPad *dst = link->dstpad;
 +    int64_t pts;
      AVFilterBufferRef *buf_out;
++    int ret;
  
 -    FF_DPRINTF_START(NULL, filter_samples); ff_dlog_link(NULL, link, 1);
 +    FF_TPRINTF_START(NULL, filter_samples); ff_tlog_link(NULL, link, 1);
  
      if (!(filter_samples = dst->filter_samples))
          filter_samples = default_filter_samples;
      } else
          buf_out = samplesref;
  
 -    return filter_samples(link, buf_out);
 +    link->cur_buf = buf_out;
 +    pts = buf_out->pts;
-     filter_samples(link, buf_out);
++    ret = filter_samples(link, buf_out);
 +    ff_update_link_current_pts(link, pts);
++    return ret;
  }
  
- void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
++int ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
 +{
 +    int insamples = samplesref->audio->nb_samples, inpos = 0, nb_samples;
 +    AVFilterBufferRef *pbuf = link->partial_buf;
 +    int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
++    int ret = 0;
 +
 +    if (!link->min_samples ||
 +        (!pbuf &&
 +         insamples >= link->min_samples && insamples <= link->max_samples)) {
-         ff_filter_samples_framed(link, samplesref);
-         return;
++        return ff_filter_samples_framed(link, samplesref);
 +    }
 +    /* Handle framing (min_samples, max_samples) */
 +    while (insamples) {
 +        if (!pbuf) {
 +            AVRational samples_tb = { 1, link->sample_rate };
 +            int perms = link->dstpad->min_perms | AV_PERM_WRITE;
 +            pbuf = ff_get_audio_buffer(link, perms, link->partial_buf_size);
 +            if (!pbuf) {
 +                av_log(link->dst, AV_LOG_WARNING,
 +                       "Samples dropped due to memory allocation failure.\n");
-                 return;
++                return 0;
 +            }
 +            avfilter_copy_buffer_ref_props(pbuf, samplesref);
 +            pbuf->pts = samplesref->pts +
 +                        av_rescale_q(inpos, samples_tb, link->time_base);
 +            pbuf->audio->nb_samples = 0;
 +        }
 +        nb_samples = FFMIN(insamples,
 +                           link->partial_buf_size - pbuf->audio->nb_samples);
 +        av_samples_copy(pbuf->extended_data, samplesref->extended_data,
 +                        pbuf->audio->nb_samples, inpos,
 +                        nb_samples, nb_channels, link->format);
 +        inpos                   += nb_samples;
 +        insamples               -= nb_samples;
 +        pbuf->audio->nb_samples += nb_samples;
 +        if (pbuf->audio->nb_samples >= link->min_samples) {
-             ff_filter_samples_framed(link, pbuf);
++            ret = ff_filter_samples_framed(link, pbuf);
 +            pbuf = NULL;
 +        }
 +    }
 +    avfilter_unref_buffer(samplesref);
 +    link->partial_buf = pbuf;
++    return ret;
 +}
@@@ -70,14 -49,10 +70,17 @@@ AVFilterBufferRef *ff_get_audio_buffer(
   * @param samplesref a reference to the buffer of audio samples being sent. The
   *                   receiving filter will free this reference when it no longer
   *                   needs it or pass it on to the next filter.
+  *
+  * @return >= 0 on success, a negative AVERROR on error. The receiving filter
+  * is responsible for unreferencing samplesref in case of error.
   */
void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref);
int ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref);
  
- void ff_filter_samples_framed(AVFilterLink *link,
 +/**
 + * Send a buffer of audio samples to the next link, without checking
 + * min_samples.
 + */
++int ff_filter_samples_framed(AVFilterLink *link,
 +                              AVFilterBufferRef *samplesref);
 +
  #endif /* AVFILTER_AUDIO_H */
index f0ebbf3,0000000..9a267a6
mode 100644,000000..100644
--- /dev/null
@@@ -1,257 -1,0 +1,258 @@@
- static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +/*
 + * Copyright (c) 2012 Stefano Sabatini
 + *
 + * 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
 + * audio to video transmedia filter
 + */
 +
 +#include "libavutil/audioconvert.h"
 +#include "libavutil/opt.h"
 +#include "libavutil/parseutils.h"
 +#include "avfilter.h"
 +#include "formats.h"
 +#include "audio.h"
 +#include "video.h"
 +#include "internal.h"
 +
 +typedef struct {
 +    const AVClass *class;
 +    int w, h;
 +    char *rate_str;
 +    AVRational rate;
 +    int buf_idx;
 +    AVFilterBufferRef *outpicref;
 +    int req_fullfilled;
 +    int n;
 +    int sample_count_mod;
 +} ShowWavesContext;
 +
 +#define OFFSET(x) offsetof(ShowWavesContext, x)
 +
 +static const AVOption showwaves_options[] = {
 +    { "rate", "set video rate", OFFSET(rate_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0 },
 +    { "r",    "set video rate", OFFSET(rate_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0 },
 +    { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "600x240"}, 0, 0 },
 +    { "s",    "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "600x240"}, 0, 0 },
 +    { "n",    "set how many samples to show in the same point", OFFSET(n), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX},
 +    { NULL },
 +};
 +
 +AVFILTER_DEFINE_CLASS(showwaves);
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args)
 +{
 +    ShowWavesContext *showwaves = ctx->priv;
 +    int err;
 +
 +    showwaves->class = &showwaves_class;
 +    av_opt_set_defaults(showwaves);
 +    showwaves->buf_idx = 0;
 +
 +    if ((err = av_set_options_string(showwaves, args, "=", ":")) < 0) {
 +        av_log(ctx, AV_LOG_ERROR, "Error parsing options string: '%s'\n", args);
 +        return err;
 +    }
 +
 +    return 0;
 +}
 +
 +static av_cold void uninit(AVFilterContext *ctx)
 +{
 +    ShowWavesContext *showwaves = ctx->priv;
 +
 +    av_freep(&showwaves->rate_str);
 +    avfilter_unref_bufferp(&showwaves->outpicref);
 +}
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    AVFilterFormats *formats = NULL;
 +    AVFilterChannelLayouts *layouts = NULL;
 +    AVFilterLink *inlink = ctx->inputs[0];
 +    AVFilterLink *outlink = ctx->outputs[0];
 +    static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, -1 };
 +    static const enum PixelFormat pix_fmts[] = { PIX_FMT_GRAY8, -1 };
 +
 +    /* set input audio formats */
 +    formats = ff_make_format_list(sample_fmts);
 +    if (!formats)
 +        return AVERROR(ENOMEM);
 +    ff_formats_ref(formats, &inlink->out_formats);
 +
 +    layouts = ff_all_channel_layouts();
 +    if (!layouts)
 +        return AVERROR(ENOMEM);
 +    ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts);
 +
 +    formats = ff_all_samplerates();
 +    if (!formats)
 +        return AVERROR(ENOMEM);
 +    ff_formats_ref(formats, &inlink->out_samplerates);
 +
 +    /* set output video format */
 +    formats = ff_make_format_list(pix_fmts);
 +    if (!formats)
 +        return AVERROR(ENOMEM);
 +    ff_formats_ref(formats, &outlink->in_formats);
 +
 +    return 0;
 +}
 +
 +static int config_output(AVFilterLink *outlink)
 +{
 +    AVFilterContext *ctx = outlink->src;
 +    AVFilterLink *inlink = ctx->inputs[0];
 +    ShowWavesContext *showwaves = ctx->priv;
 +    int err;
 +
 +    if (showwaves->n && showwaves->rate_str) {
 +        av_log(ctx, AV_LOG_ERROR, "Options 'n' and 'rate' cannot be set at the same time\n");
 +        return AVERROR(EINVAL);
 +    }
 +
 +    if (!showwaves->n) {
 +        if (!showwaves->rate_str)
 +            showwaves->rate = (AVRational){25,1}; /* set default value */
 +        else if ((err = av_parse_video_rate(&showwaves->rate, showwaves->rate_str)) < 0) {
 +            av_log(ctx, AV_LOG_ERROR, "Invalid frame rate: '%s'\n", showwaves->rate_str);
 +            return err;
 +        }
 +        showwaves->n = FFMAX(1, ((double)inlink->sample_rate / (showwaves->w * av_q2d(showwaves->rate))) + 0.5);
 +    }
 +
 +    outlink->w = showwaves->w;
 +    outlink->h = showwaves->h;
 +    outlink->sample_aspect_ratio = (AVRational){1,1};
 +
 +    outlink->frame_rate = av_div_q((AVRational){inlink->sample_rate,showwaves->n},
 +                                   (AVRational){showwaves->w,1});
 +
 +    av_log(ctx, AV_LOG_INFO, "s:%dx%d r:%f n:%d\n",
 +           showwaves->w, showwaves->h, av_q2d(outlink->frame_rate), showwaves->n);
 +    return 0;
 +}
 +
 +inline static void push_frame(AVFilterLink *outlink)
 +{
 +    ShowWavesContext *showwaves = outlink->src->priv;
 +
 +    ff_start_frame(outlink, showwaves->outpicref);
 +    ff_draw_slice(outlink, 0, outlink->h, 1);
 +    ff_end_frame(outlink);
 +    showwaves->req_fullfilled = 1;
 +    showwaves->outpicref = NULL;
 +    showwaves->buf_idx = 0;
 +}
 +
 +static int request_frame(AVFilterLink *outlink)
 +{
 +    ShowWavesContext *showwaves = outlink->src->priv;
 +    AVFilterLink *inlink = outlink->src->inputs[0];
 +    int ret;
 +
 +    showwaves->req_fullfilled = 0;
 +    do {
 +        ret = ff_request_frame(inlink);
 +    } while (!showwaves->req_fullfilled && ret >= 0);
 +
 +    if (ret == AVERROR_EOF && showwaves->outpicref)
 +        push_frame(outlink);
 +    return ret;
 +}
 +
 +#define MAX_INT16 ((1<<15) -1)
 +
++static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +{
 +    AVFilterContext *ctx = inlink->dst;
 +    AVFilterLink *outlink = ctx->outputs[0];
 +    ShowWavesContext *showwaves = ctx->priv;
 +    const int nb_samples = insamples->audio->nb_samples;
 +    AVFilterBufferRef *outpicref = showwaves->outpicref;
 +    int linesize = outpicref ? outpicref->linesize[0] : 0;
 +    int16_t *p = (int16_t *)insamples->data[0];
 +    int nb_channels = av_get_channel_layout_nb_channels(insamples->audio->channel_layout);
 +    int i, j, h;
 +    const int n = showwaves->n;
 +    const int x = 255 / (nb_channels * n); /* multiplication factor, pre-computed to avoid in-loop divisions */
 +
 +    /* draw data in the buffer */
 +    for (i = 0; i < nb_samples; i++) {
 +        if (showwaves->buf_idx == 0 && showwaves->sample_count_mod == 0) {
 +            showwaves->outpicref = outpicref =
 +                ff_get_video_buffer(outlink, AV_PERM_WRITE|AV_PERM_ALIGN,
 +                                    outlink->w, outlink->h);
 +            outpicref->video->w = outlink->w;
 +            outpicref->video->h = outlink->h;
 +            outpicref->pts = insamples->pts +
 +                             av_rescale_q((p - (int16_t *)insamples->data[0]) / nb_channels,
 +                                          (AVRational){ 1, inlink->sample_rate },
 +                                          outlink->time_base);
 +            outlink->out_buf = outpicref;
 +            linesize = outpicref->linesize[0];
 +            memset(outpicref->data[0], 0, showwaves->h*linesize);
 +        }
 +        for (j = 0; j < nb_channels; j++) {
 +            h = showwaves->h/2 - av_rescale(*p++, showwaves->h/2, MAX_INT16);
 +            if (h >= 0 && h < outlink->h)
 +                *(outpicref->data[0] + showwaves->buf_idx + h * linesize) += x;
 +        }
 +        showwaves->sample_count_mod++;
 +        if (showwaves->sample_count_mod == n) {
 +            showwaves->sample_count_mod = 0;
 +            showwaves->buf_idx++;
 +        }
 +        if (showwaves->buf_idx == showwaves->w)
 +            push_frame(outlink);
 +    }
 +
 +    avfilter_unref_buffer(insamples);
++    return 0;
 +}
 +
 +AVFilter avfilter_avf_showwaves = {
 +    .name           = "showwaves",
 +    .description    = NULL_IF_CONFIG_SMALL("Convert input audio to a video output."),
 +    .init           = init,
 +    .uninit         = uninit,
 +    .query_formats  = query_formats,
 +    .priv_size      = sizeof(ShowWavesContext),
 +
 +    .inputs  = (const AVFilterPad[]) {
 +        {
 +            .name           = "default",
 +            .type           = AVMEDIA_TYPE_AUDIO,
 +            .filter_samples = filter_samples,
 +            .min_perms      = AV_PERM_READ,
 +        },
 +        { .name = NULL }
 +    },
 +
 +    .outputs = (const AVFilterPad[]) {
 +        {
 +            .name           = "default",
 +            .type           = AVMEDIA_TYPE_VIDEO,
 +            .config_props   = config_output,
 +            .request_frame  = request_frame,
 +        },
 +        { .name = NULL }
 +    },
 +};
Simple merge
Simple merge
Simple merge
index 6549a5c,0000000..3ba35be
mode 100644,000000..100644
--- /dev/null
@@@ -1,185 -1,0 +1,185 @@@
- static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +/*
 + * Copyright (c) 2010 Stefano Sabatini
 + *
 + * 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
 + * Set timebase for the output link.
 + */
 +
 +#include "libavutil/avstring.h"
 +#include "libavutil/eval.h"
 +#include "libavutil/mathematics.h"
 +#include "libavutil/rational.h"
 +#include "avfilter.h"
 +#include "internal.h"
 +#include "audio.h"
 +#include "video.h"
 +
 +static const char *const var_names[] = {
 +    "AVTB",   /* default timebase 1/AV_TIME_BASE */
 +    "intb",   /* input timebase */
 +    "sr",     /* sample rate */
 +    NULL
 +};
 +
 +enum var_name {
 +    VAR_AVTB,
 +    VAR_INTB,
 +    VAR_SR,
 +    VAR_VARS_NB
 +};
 +
 +typedef struct {
 +    char tb_expr[256];
 +    double var_values[VAR_VARS_NB];
 +} SetTBContext;
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args)
 +{
 +    SetTBContext *settb = ctx->priv;
 +    av_strlcpy(settb->tb_expr, "intb", sizeof(settb->tb_expr));
 +
 +    if (args)
 +        sscanf(args, "%255[^:]", settb->tb_expr);
 +
 +    return 0;
 +}
 +
 +static int config_output_props(AVFilterLink *outlink)
 +{
 +    AVFilterContext *ctx = outlink->src;
 +    SetTBContext *settb = ctx->priv;
 +    AVFilterLink *inlink = ctx->inputs[0];
 +    AVRational time_base;
 +    int ret;
 +    double res;
 +
 +    settb->var_values[VAR_AVTB] = av_q2d(AV_TIME_BASE_Q);
 +    settb->var_values[VAR_INTB] = av_q2d(inlink->time_base);
 +    settb->var_values[VAR_SR]   = inlink->sample_rate;
 +
 +    outlink->w = inlink->w;
 +    outlink->h = inlink->h;
 +
 +    if ((ret = av_expr_parse_and_eval(&res, settb->tb_expr, var_names, settb->var_values,
 +                                      NULL, NULL, NULL, NULL, NULL, 0, NULL)) < 0) {
 +        av_log(ctx, AV_LOG_ERROR, "Invalid expression '%s' for timebase.\n", settb->tb_expr);
 +        return ret;
 +    }
 +    time_base = av_d2q(res, INT_MAX);
 +    if (time_base.num <= 0 || time_base.den <= 0) {
 +        av_log(ctx, AV_LOG_ERROR,
 +               "Invalid non-positive values for the timebase num:%d or den:%d.\n",
 +               time_base.num, time_base.den);
 +        return AVERROR(EINVAL);
 +    }
 +
 +    outlink->time_base = time_base;
 +    av_log(outlink->src, AV_LOG_VERBOSE, "tb:%d/%d -> tb:%d/%d\n",
 +           inlink ->time_base.num, inlink ->time_base.den,
 +           outlink->time_base.num, outlink->time_base.den);
 +
 +    return 0;
 +}
 +
 +static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
 +{
 +    AVFilterContext *ctx = inlink->dst;
 +    AVFilterLink *outlink = ctx->outputs[0];
 +    AVFilterBufferRef *picref2 = picref;
 +
 +    if (av_cmp_q(inlink->time_base, outlink->time_base)) {
 +        picref2 = avfilter_ref_buffer(picref, ~0);
 +        picref2->pts = av_rescale_q(picref->pts, inlink->time_base, outlink->time_base);
 +        av_log(ctx, AV_LOG_DEBUG, "tb:%d/%d pts:%"PRId64" -> tb:%d/%d pts:%"PRId64"\n",
 +               inlink ->time_base.num, inlink ->time_base.den, picref ->pts,
 +               outlink->time_base.num, outlink->time_base.den, picref2->pts);
 +        avfilter_unref_buffer(picref);
 +    }
 +
 +    ff_start_frame(outlink, picref2);
 +}
 +
-     ff_filter_samples(outlink, outsamples);
++static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +{
 +    AVFilterContext *ctx = inlink->dst;
 +    AVFilterLink *outlink = ctx->outputs[0];
 +    AVFilterBufferRef *outsamples = insamples;
 +
 +    if (av_cmp_q(inlink->time_base, outlink->time_base)) {
 +        outsamples = avfilter_ref_buffer(insamples, ~0);
 +        outsamples->pts = av_rescale_q(insamples->pts, inlink->time_base, outlink->time_base);
 +        av_log(ctx, AV_LOG_DEBUG, "tb:%d/%d pts:%"PRId64" -> tb:%d/%d pts:%"PRId64"\n",
 +               inlink ->time_base.num, inlink ->time_base.den, insamples ->pts,
 +               outlink->time_base.num, outlink->time_base.den, outsamples->pts);
 +        avfilter_unref_buffer(insamples);
 +    }
 +
++    return ff_filter_samples(outlink, outsamples);
 +}
 +
 +#if CONFIG_SETTB_FILTER
 +AVFilter avfilter_vf_settb = {
 +    .name      = "settb",
 +    .description = NULL_IF_CONFIG_SMALL("Set timebase for the video output link."),
 +    .init      = init,
 +
 +    .priv_size = sizeof(SetTBContext),
 +
 +    .inputs    = (const AVFilterPad[]) {
 +        { .name             = "default",
 +          .type             = AVMEDIA_TYPE_VIDEO,
 +          .get_video_buffer = ff_null_get_video_buffer,
 +          .start_frame      = start_frame,
 +          .end_frame        = ff_null_end_frame },
 +        { .name = NULL }
 +    },
 +    .outputs   = (const AVFilterPad[]) {
 +        { .name            = "default",
 +          .type            = AVMEDIA_TYPE_VIDEO,
 +          .config_props    = config_output_props, },
 +        { .name = NULL}
 +    },
 +};
 +#endif
 +
 +#if CONFIG_ASETTB_FILTER
 +AVFilter avfilter_af_asettb = {
 +    .name      = "asettb",
 +    .description = NULL_IF_CONFIG_SMALL("Set timebase for the audio output link."),
 +    .init      = init,
 +
 +    .priv_size = sizeof(SetTBContext),
 +
 +    .inputs    = (const AVFilterPad[]) {
 +        { .name             = "default",
 +          .type             = AVMEDIA_TYPE_AUDIO,
 +          .get_audio_buffer = ff_null_get_audio_buffer,
 +          .filter_samples   = filter_samples, },
 +        { .name = NULL }
 +    },
 +    .outputs   = (const AVFilterPad[]) {
 +        { .name            = "default",
 +          .type            = AVMEDIA_TYPE_AUDIO,
 +          .config_props    = config_output_props, },
 +        { .name = NULL}
 +    },
 +};
 +#endif
@@@ -258,10 -268,10 +268,10 @@@ AVFilter avfilter_vf_fifo = 
  
      .priv_size = sizeof(FifoContext),
  
 -    .inputs    = (AVFilterPad[]) {{ .name            = "default",
 +    .inputs    = (const AVFilterPad[]) {{ .name      = "default",
                                      .type            = AVMEDIA_TYPE_VIDEO,
                                      .get_video_buffer= ff_null_get_video_buffer,
-                                     .start_frame     = add_to_queue,
+                                     .start_frame     = start_frame,
                                      .draw_slice      = draw_slice,
                                      .end_frame       = end_frame,
                                      .rej_perms       = AV_PERM_REUSE2, },
Simple merge
index 8275f80,0000000..ceae112
mode 100644,000000..100644
--- /dev/null
@@@ -1,325 -1,0 +1,326 @@@
- static void filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
 +/*
 + * Copyright (c) 2011 Stefano Sabatini
 + *
 + * 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
 + * buffer sink
 + */
 +
 +#include "libavutil/avassert.h"
 +#include "libavutil/fifo.h"
 +#include "avfilter.h"
 +#include "buffersink.h"
 +#include "internal.h"
 +
 +AVBufferSinkParams *av_buffersink_params_alloc(void)
 +{
 +    static const int pixel_fmts[] = { -1 };
 +    AVBufferSinkParams *params = av_malloc(sizeof(AVBufferSinkParams));
 +    if (!params)
 +        return NULL;
 +
 +    params->pixel_fmts = pixel_fmts;
 +    return params;
 +}
 +
 +AVABufferSinkParams *av_abuffersink_params_alloc(void)
 +{
 +    static const int sample_fmts[] = { -1 };
 +    static const int64_t channel_layouts[] = { -1 };
 +    AVABufferSinkParams *params = av_malloc(sizeof(AVABufferSinkParams));
 +
 +    if (!params)
 +        return NULL;
 +
 +    params->sample_fmts = sample_fmts;
 +    params->channel_layouts = channel_layouts;
 +    return params;
 +}
 +
 +typedef struct {
 +    AVFifoBuffer *fifo;                      ///< FIFO buffer of video frame references
 +    unsigned warning_limit;
 +
 +    /* only used for video */
 +    enum PixelFormat *pixel_fmts;           ///< list of accepted pixel formats, must be terminated with -1
 +
 +    /* only used for audio */
 +    enum AVSampleFormat *sample_fmts;       ///< list of accepted sample formats, terminated by AV_SAMPLE_FMT_NONE
 +    int64_t *channel_layouts;               ///< list of accepted channel layouts, terminated by -1
 +} BufferSinkContext;
 +
 +#define FIFO_INIT_SIZE 8
 +
 +static av_cold int common_init(AVFilterContext *ctx)
 +{
 +    BufferSinkContext *buf = ctx->priv;
 +
 +    buf->fifo = av_fifo_alloc(FIFO_INIT_SIZE*sizeof(AVFilterBufferRef *));
 +    if (!buf->fifo) {
 +        av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo\n");
 +        return AVERROR(ENOMEM);
 +    }
 +    buf->warning_limit = 100;
 +    return 0;
 +}
 +
 +static av_cold void common_uninit(AVFilterContext *ctx)
 +{
 +    BufferSinkContext *buf = ctx->priv;
 +    AVFilterBufferRef *picref;
 +
 +    if (buf->fifo) {
 +        while (av_fifo_size(buf->fifo) >= sizeof(AVFilterBufferRef *)) {
 +            av_fifo_generic_read(buf->fifo, &picref, sizeof(picref), NULL);
 +            avfilter_unref_buffer(picref);
 +        }
 +        av_fifo_free(buf->fifo);
 +        buf->fifo = NULL;
 +    }
 +}
 +
 +static void end_frame(AVFilterLink *inlink)
 +{
 +    AVFilterContext *ctx = inlink->dst;
 +    BufferSinkContext *buf = inlink->dst->priv;
 +
 +    av_assert1(inlink->cur_buf);
 +    if (av_fifo_space(buf->fifo) < sizeof(AVFilterBufferRef *)) {
 +        /* realloc fifo size */
 +        if (av_fifo_realloc2(buf->fifo, av_fifo_size(buf->fifo) * 2) < 0) {
 +            av_log(ctx, AV_LOG_ERROR,
 +                   "Cannot buffer more frames. Consume some available frames "
 +                   "before adding new ones.\n");
 +            return;
 +        }
 +    }
 +
 +    /* cache frame */
 +    av_fifo_generic_write(buf->fifo,
 +                          &inlink->cur_buf, sizeof(AVFilterBufferRef *), NULL);
 +    if (buf->warning_limit &&
 +        av_fifo_size(buf->fifo) / sizeof(AVFilterBufferRef *) >= buf->warning_limit) {
 +        av_log(ctx, AV_LOG_WARNING,
 +               "%d buffers queued in %s, something may be wrong.\n",
 +               buf->warning_limit,
 +               (char *)av_x_if_null(ctx->name, ctx->filter->name));
 +        buf->warning_limit *= 10;
 +    }
 +}
 +
 +void av_buffersink_set_frame_size(AVFilterContext *ctx, unsigned frame_size)
 +{
 +    AVFilterLink *inlink = ctx->inputs[0];
 +
 +    inlink->min_samples = inlink->max_samples =
 +    inlink->partial_buf_size = frame_size;
 +}
 +
 +int av_buffersink_get_buffer_ref(AVFilterContext *ctx,
 +                                  AVFilterBufferRef **bufref, int flags)
 +{
 +    BufferSinkContext *buf = ctx->priv;
 +    AVFilterLink *inlink = ctx->inputs[0];
 +    int ret;
 +    *bufref = NULL;
 +
 +    av_assert0(!strcmp(ctx->filter->name, "buffersink") || !strcmp(ctx->filter->name, "abuffersink"));
 +
 +    /* no picref available, fetch it from the filterchain */
 +    if (!av_fifo_size(buf->fifo)) {
 +        if (flags & AV_BUFFERSINK_FLAG_NO_REQUEST)
 +            return AVERROR(EAGAIN);
 +        if ((ret = ff_request_frame(inlink)) < 0)
 +            return ret;
 +    }
 +
 +    if (!av_fifo_size(buf->fifo))
 +        return AVERROR(EINVAL);
 +
 +    if (flags & AV_BUFFERSINK_FLAG_PEEK)
 +        *bufref = *((AVFilterBufferRef **)av_fifo_peek2(buf->fifo, 0));
 +    else
 +        av_fifo_generic_read(buf->fifo, bufref, sizeof(*bufref), NULL);
 +
 +    return 0;
 +}
 +
 +AVRational av_buffersink_get_frame_rate(AVFilterContext *ctx)
 +{
 +    av_assert0(!strcmp(ctx->filter->name, "buffersink"));
 +
 +    return ctx->inputs[0]->frame_rate;
 +}
 +
 +int av_buffersink_poll_frame(AVFilterContext *ctx)
 +{
 +    BufferSinkContext *buf = ctx->priv;
 +    AVFilterLink *inlink = ctx->inputs[0];
 +
 +    av_assert0(!strcmp(ctx->filter->name, "buffersink") || !strcmp(ctx->filter->name, "abuffersink"));
 +
 +    return av_fifo_size(buf->fifo)/sizeof(AVFilterBufferRef *) + ff_poll_frame(inlink);
 +}
 +
 +#if CONFIG_BUFFERSINK_FILTER
 +
 +static av_cold int vsink_init(AVFilterContext *ctx, const char *args)
 +{
 +    BufferSinkContext *buf = ctx->priv;
 +    AVBufferSinkParams *params = NULL;
 +
 +//     if(args && !strcmp(args, "opaque"))
 +//         params = (AVBufferSinkParams *)(args+7);
 +
 +    if (!params) {
 +        av_log(ctx, AV_LOG_WARNING,
 +               "No opaque field provided\n");
 +        buf->pixel_fmts = NULL;
 +    } else {
 +        const int *pixel_fmts = params->pixel_fmts;
 +
 +        buf->pixel_fmts = ff_copy_int_list(pixel_fmts);
 +        if (!buf->pixel_fmts)
 +            return AVERROR(ENOMEM);
 +    }
 +
 +    return common_init(ctx);
 +}
 +
 +static av_cold void vsink_uninit(AVFilterContext *ctx)
 +{
 +    BufferSinkContext *buf = ctx->priv;
 +    av_freep(&buf->pixel_fmts);
 +    common_uninit(ctx);
 +}
 +
 +static int vsink_query_formats(AVFilterContext *ctx)
 +{
 +    BufferSinkContext *buf = ctx->priv;
 +
 +    if (buf->pixel_fmts)
 +        ff_set_common_formats(ctx, ff_make_format_list(buf->pixel_fmts));
 +    else
 +        ff_default_query_formats(ctx);
 +
 +    return 0;
 +}
 +
 +AVFilter avfilter_vsink_buffersink = {
 +    .name      = "buffersink",
 +    .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
 +    .priv_size = sizeof(BufferSinkContext),
 +    .init      = vsink_init,
 +    .uninit    = vsink_uninit,
 +
 +    .query_formats = vsink_query_formats,
 +
 +    .inputs    = (const AVFilterPad[]) {{ .name    = "default",
 +                                    .type          = AVMEDIA_TYPE_VIDEO,
 +                                    .end_frame     = end_frame,
 +                                    .min_perms     = AV_PERM_READ, },
 +                                  { .name = NULL }},
 +    .outputs   = (const AVFilterPad[]) {{ .name = NULL }},
 +};
 +
 +#endif /* CONFIG_BUFFERSINK_FILTER */
 +
 +#if CONFIG_ABUFFERSINK_FILTER
 +
++static int filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
 +{
 +    end_frame(link);
++    return 0;
 +}
 +
 +static av_cold int asink_init(AVFilterContext *ctx, const char *args)
 +{
 +    BufferSinkContext *buf = ctx->priv;
 +    AVABufferSinkParams *params = NULL;
 +
 +//     if(args && !strcmp(args, "opaque"))
 +//         params = (AVABufferSinkParams *)(args+7);
 +
 +    if (params && params->sample_fmts) {
 +        buf->sample_fmts     = ff_copy_int_list  (params->sample_fmts);
 +        if (!buf->sample_fmts)
 +            goto fail_enomem;
 +    }
 +    if (params && params->channel_layouts) {
 +        buf->channel_layouts = ff_copy_int64_list(params->channel_layouts);
 +        if (!buf->channel_layouts)
 +            goto fail_enomem;
 +    }
 +    if (!common_init(ctx))
 +        return 0;
 +
 +fail_enomem:
 +    av_freep(&buf->sample_fmts);
 +    av_freep(&buf->channel_layouts);
 +    return AVERROR(ENOMEM);
 +}
 +
 +static av_cold void asink_uninit(AVFilterContext *ctx)
 +{
 +    BufferSinkContext *buf = ctx->priv;
 +
 +    av_freep(&buf->sample_fmts);
 +    av_freep(&buf->channel_layouts);
 +    common_uninit(ctx);
 +}
 +
 +static int asink_query_formats(AVFilterContext *ctx)
 +{
 +    BufferSinkContext *buf = ctx->priv;
 +    AVFilterFormats *formats = NULL;
 +    AVFilterChannelLayouts *layouts = NULL;
 +
 +    if (buf->sample_fmts) {
 +    if (!(formats = ff_make_format_list(buf->sample_fmts)))
 +        return AVERROR(ENOMEM);
 +    ff_set_common_formats(ctx, formats);
 +    }
 +
 +    if (buf->channel_layouts) {
 +    if (!(layouts = avfilter_make_format64_list(buf->channel_layouts)))
 +        return AVERROR(ENOMEM);
 +    ff_set_common_channel_layouts(ctx, layouts);
 +    }
 +
 +    return 0;
 +}
 +
 +AVFilter avfilter_asink_abuffersink = {
 +    .name      = "abuffersink",
 +    .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
 +    .init      = asink_init,
 +    .uninit    = asink_uninit,
 +    .priv_size = sizeof(BufferSinkContext),
 +    .query_formats = asink_query_formats,
 +
 +    .inputs    = (const AVFilterPad[]) {{ .name     = "default",
 +                                    .type           = AVMEDIA_TYPE_AUDIO,
 +                                    .filter_samples = filter_samples,
 +                                    .min_perms      = AV_PERM_READ, },
 +                                  { .name = NULL }},
 +    .outputs   = (const AVFilterPad[]) {{ .name = NULL }},
 +};
 +
 +#endif /* CONFIG_ABUFFERSINK_FILTER */
Simple merge
Simple merge
@@@ -43,7 -43,7 +43,7 @@@ static int tcp_open(URLContext *h, cons
      char buf[256];
      int ret;
      socklen_t optlen;
-     int timeout = 50;
 -    int timeout = 100, listen_timeout = -1;
++    int timeout = 50, listen_timeout = -1;
      char hostname[1024],proto[1024],path[1024];
      char portstr[10];
  
index 0000000,5b0fbec..06da90f
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,102 +1,102 @@@
 - * This file is part of Libav.
+ /*
+  * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
+  *
 - * Libav is free software; you can redistribute it and/or
++ * This file is part of FFmpeg.
+  *
 - * Libav is distributed in the hope that it will be useful,
++ * 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.
+  *
 - * License along with Libav; if not, write to the Free Software
++ * 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
+  */
+ #if defined(CONFIG_RESAMPLE_DBL)
+ #define SET_TYPE(func)  func ## _dbl
+ #define FELEM         double
+ #define FELEM2        double
+ #define FELEML        double
+ #define OUT(d, v) d = v
+ #define DBL_TO_FELEM(d, v) d = v
+ #elif defined(CONFIG_RESAMPLE_FLT)
+ #define SET_TYPE(func)  func ## _flt
+ #define FELEM         float
+ #define FELEM2        float
+ #define FELEML        float
+ #define OUT(d, v) d = v
+ #define DBL_TO_FELEM(d, v) d = v
+ #elif defined(CONFIG_RESAMPLE_S32)
+ #define SET_TYPE(func)  func ## _s32
+ #define FELEM         int32_t
+ #define FELEM2        int64_t
+ #define FELEML        int64_t
+ #define OUT(d, v) d = av_clipl_int32((v + (1 << 29)) >> 30)
+ #define DBL_TO_FELEM(d, v) d = av_clipl_int32(llrint(v * (1 << 30)));
+ #else
+ #define SET_TYPE(func)  func ## _s16
+ #define FELEM         int16_t
+ #define FELEM2        int32_t
+ #define FELEML        int64_t
+ #define OUT(d, v) d = av_clip_int16((v + (1 << 14)) >> 15)
+ #define DBL_TO_FELEM(d, v) d = av_clip_int16(lrint(v * (1 << 15)))
+ #endif
+ static void SET_TYPE(resample_one)(ResampleContext *c, int no_filter,
+                                    void *dst0, int dst_index, const void *src0,
+                                    int src_size, int index, int frac)
+ {
+     FELEM *dst = dst0;
+     const FELEM *src = src0;
+     if (no_filter) {
+         dst[dst_index] = src[index];
+     } else {
+         int i;
+         int sample_index = index >> c->phase_shift;
+         FELEM2 val = 0;
+         FELEM *filter = ((FELEM *)c->filter_bank) +
+                         c->filter_length * (index & c->phase_mask);
+         if (sample_index < 0) {
+             for (i = 0; i < c->filter_length; i++)
+                 val += src[FFABS(sample_index + i) % src_size] *
+                        (FELEM2)filter[i];
+         } else if (c->linear) {
+             FELEM2 v2 = 0;
+             for (i = 0; i < c->filter_length; i++) {
+                 val += src[abs(sample_index + i)] * (FELEM2)filter[i];
+                 v2  += src[abs(sample_index + i)] * (FELEM2)filter[i + c->filter_length];
+             }
+             val += (v2 - val) * (FELEML)frac / c->src_incr;
+         } else {
+             for (i = 0; i < c->filter_length; i++)
+                 val += src[sample_index + i] * (FELEM2)filter[i];
+         }
+         OUT(dst[dst_index], val);
+     }
+ }
+ static void SET_TYPE(set_filter)(void *filter0, double *tab, int phase,
+                                  int tap_count)
+ {
+     int i;
+     FELEM *filter = ((FELEM *)filter0) + phase * tap_count;
+     for (i = 0; i < tap_count; i++) {
+         DBL_TO_FELEM(filter[i], tab[i]);
+     }
+ }
+ #undef SET_TYPE
+ #undef FELEM
+ #undef FELEM2
+ #undef FELEML
+ #undef OUT
+ #undef DBL_TO_FELEM
Simple merge
@@@ -71,11 -71,17 +71,17 @@@ run()
  }
  
  probefmt(){
 -    run avprobe -show_format_entry format_name -v 0 "$@"
 +    run ffprobe -show_format_entry format_name -print_format default=nw=1:nk=1 -v 0 "$@"
  }
  
 -avconv(){
 +ffmpeg(){
-     run ffmpeg -nostats -threads $threads -thread_type $thread_type -cpuflags $cpuflags "$@"
+     dec_opts="-threads $threads -thread_type $thread_type"
 -    avconv_args="-nostats -cpuflags $cpuflags"
++    ffmpeg_args="-nostats -cpuflags $cpuflags"
+     for arg in $@; do
 -        [ ${arg} = -i ] && avconv_args="${avconv_args} ${dec_opts}"
 -        avconv_args="${avconv_args} ${arg}"
++        [ ${arg} = -i ] && ffmpeg_args="${ffmpeg_args} ${dec_opts}"
++        ffmpeg_args="${ffmpeg_args} ${arg}"
+     done
 -    run avconv ${avconv_args}
++    run ffmpeg ${ffmpeg_args}
  }
  
  framecrc(){