Merge remote-tracking branch 'qatar/master'
authorMichael Niedermayer <michaelni@gmx.at>
Sun, 24 Jun 2012 00:09:53 +0000 (02:09 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Sun, 24 Jun 2012 00:09:53 +0000 (02:09 +0200)
* qatar/master:
  x86: Only use optimizations with cmov if the CPU supports the instruction
  x86: Add CPU flag for the i686 cmov instruction
  x86: remove unused inline asm macros from dsputil_mmx.h
  x86: move some inline asm macros to the only places they are used
  lavfi: Add the af_channelmap audio channel mapping filter.
  lavfi: add join audio filter.
  lavfi: allow audio filters to request a given number of samples.
  lavfi: support automatically inserting the fifo filter when needed.
  lavfi/audio: eliminate ff_default_filter_samples().

Conflicts:
Changelog
libavcodec/x86/h264dsp_mmx.c
libavfilter/Makefile
libavfilter/allfilters.c
libavfilter/avfilter.h
libavfilter/avfiltergraph.c
libavfilter/version.h
libavutil/x86/cpu.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
43 files changed:
1  2 
Changelog
doc/APIchanges
doc/filters.texi
libavcodec/x86/cavsdsp_mmx.c
libavcodec/x86/dsputil_mmx.c
libavcodec/x86/dsputil_mmx.h
libavcodec/x86/h264dsp_mmx.c
libavfilter/Makefile
libavfilter/af_aconvert.c
libavfilter/af_aformat.c
libavfilter/af_amerge.c
libavfilter/af_anull.c
libavfilter/af_aresample.c
libavfilter/af_asetnsamples.c
libavfilter/af_astreamsync.c
libavfilter/af_atempo.c
libavfilter/af_channelmap.c
libavfilter/af_pan.c
libavfilter/allfilters.c
libavfilter/audio.c
libavfilter/audio.h
libavfilter/avf_showwaves.c
libavfilter/avfilter.h
libavfilter/avfiltergraph.c
libavfilter/avfiltergraph.h
libavfilter/buffersink.c
libavfilter/defaults.c
libavfilter/fifo.c
libavfilter/formats.c
libavfilter/internal.h
libavfilter/libmpcodecs/vf_uspp.c
libavfilter/sink_buffer.c
libavfilter/version.h
libavfilter/vf_blackdetect.c
libavfilter/vf_idet.c
libavfilter/vf_mp.c
libavfilter/vf_thumbnail.c
libavfilter/vf_tile.c
libavfilter/vf_tinterlace.c
libavfilter/video.c
libavutil/cpu.c
libavutil/cpu.h
libavutil/x86/cpu.c

diff --cc Changelog
+++ b/Changelog
  Entries are sorted chronologically from oldest to youngest within each release,
  releases are sorted from youngest to oldest.
  
 -version <next>:
 +version next:
 +- INI and flat output in ffprobe
 +- Scene detection in libavfilter
 +- Indeo Audio decoder
 +- channelsplit audio filter
 +- setnsamples audio filter
 +- atempo filter
 +- ffprobe -show_data option
 +- RTMPT protocol support
 +- iLBC encoding/decoding via libilbc
 +- Microsoft Screen 1 decoder
++- join audio filter
++- audio channel mapping filter
 +- showwaves filter
 +- LucasArts SMUSH playback support
  
 -- XWD encoder and decoder
 -- Support for fragmentation in the mov/mp4 muxer
 -- ISMV (Smooth Streaming) muxer
 +
 +version 0.11:
 +
 +- Fixes: CVE-2012-2772, CVE-2012-2774, CVE-2012-2775, CVE-2012-2776, CVE-2012-2777,
 +         CVE-2012-2779, CVE-2012-2782, CVE-2012-2783, CVE-2012-2784, CVE-2012-2785,
 +         CVE-2012-2786, CVE-2012-2787, CVE-2012-2788, CVE-2012-2789, CVE-2012-2790,
 +         CVE-2012-2791, CVE-2012-2792, CVE-2012-2793, CVE-2012-2794, CVE-2012-2795,
 +         CVE-2012-2796, CVE-2012-2797, CVE-2012-2798, CVE-2012-2799, CVE-2012-2800,
 +         CVE-2012-2801, CVE-2012-2802, CVE-2012-2803, CVE-2012-2804,
 +- v408 Quicktime and Microsoft AYUV Uncompressed 4:4:4:4 encoder and decoder
 +- setfield filter
  - CDXL demuxer and decoder
  - Apple ProRes encoder
 +- ffprobe -count_packets and -count_frames options
  - Sun Rasterfile Encoder
 -- remove libpostproc
  - ID3v2 attached pictures reading and writing
  - WMA Lossless decoder
 -- XBM encoder
 +- bluray protocol
 +- blackdetect filter
 +- libutvideo encoder wrapper (--enable-libutvideo)
 +- swapuv filter
 +- bbox filter
 +- XBM encoder and decoder
  - RealAudio Lossless decoder
  - ZeroCodec decoder
 -- drop support for avconv without libavfilter
 -- add libavresample audio conversion library
 -- audio filters support in libavfilter and avconv
 +- tile video filter
 +- Metal Gear Solid: The Twin Snakes demuxer
 +- OpenEXR image decoder
 +- removelogo filter
 +- drop support for ffmpeg without libavfilter
 +- drawtext video filter: fontconfig support
 +- ffmpeg -benchmark_all option
 +- super2xsai filter ported from libmpcodecs
 +- add libavresample audio conversion library for compatibility
 +- MicroDVD decoder
 +- Avid Meridien (AVUI) encoder and decoder
 +- accept + prefix to -pix_fmt option to disable automatic conversions.
 +- complete audio filtering in libavfilter and ffmpeg
  - add fps filter
 -- audio split filter
 +- vorbis parser
 +- png parser
  - audio mix filter
 -- avprobe output is now standard INI or JSON. The old format can still
 -  be used with -of old.
 -- Indeo Audio decoder
 -- channelsplit audio filter
 -- RTMPT protocol support
 -- iLBC encoding/decoding via libilbc
 -- Microsoft Screen 1 decoder
 -- join audio filter
 -- audio channel mapping filter
  
  
 -version 0.8:
 +version 0.10:
  
 +- Fixes: CVE-2011-3929, CVE-2011-3934, CVE-2011-3935, CVE-2011-3936,
 +         CVE-2011-3937, CVE-2011-3940, CVE-2011-3941, CVE-2011-3944,
 +         CVE-2011-3945, CVE-2011-3946, CVE-2011-3947, CVE-2011-3949,
 +         CVE-2011-3950, CVE-2011-3951, CVE-2011-3952
 +- v410 Quicktime Uncompressed 4:4:4 10-bit encoder and decoder
 +- SBaGen (SBG) binaural beats script demuxer
 +- OpenMG Audio muxer
 +- Timecode extraction in DV and MOV
 +- thumbnail video filter
 +- XML output in ffprobe
 +- asplit audio filter
 +- tinterlace video filter
 +- astreamsync audio filter
 +- amerge audio filter
 +- ISMV (Smooth Streaming) muxer
  - GSM audio parser
  - SMJPEG muxer
 -
 -
 -version 0.8_beta2:
 -
 +- XWD encoder and decoder
  - Automatic thread count based on detection number of (available) CPU cores
 -- Deprecate libpostproc. If desired, the switch --enable-postproc will
 -  enable it but it may be removed in a later Libav release.
 +- y41p Brooktree Uncompressed 4:1:1 12-bit encoder and decoder
 +- ffprobe -show_error option
 +- Avid 1:1 10-bit RGB Packer codec
 +- v308 Quicktime Uncompressed 4:4:4 encoder and decoder
 +- yuv4 libquicktime packed 4:2:0 encoder and decoder
 +- ffprobe -show_frames option
 +- silencedetect audio filter
 +- ffprobe -show_program_version, -show_library_versions, -show_versions options
  - rv34: frame-level multi-threading
  - optimized iMDCT transform on x86 using SSE for for mpegaudiodec
 +- Improved PGS subtitle decoder
 +- dumpgraph option to lavfi device
 +- r210 and r10k encoders
 +- ffwavesynth decoder
 +- aviocat tool
 +- ffeval tool
  
  
 -version 0.8_beta1:
 +version 0.9:
  
 +- openal input device added
 +- boxblur filter added
  - BWF muxer
  - Flash Screen Video 2 decoder
 -- ffplay/ffprobe/ffserver renamed to avplay/avprobe/avserver
 -- ffmpeg deprecated, added avconv, which is almost the same for now, except
 +- lavfi input device added
 +- added avconv, which is almost the same for now, except
  for a few incompatible changes in the options, which will hopefully make them
  easier to use. The changes are:
      * The options placement is now strictly enforced! While in theory the
diff --cc doc/APIchanges
@@@ -4,11 -4,9 +4,11 @@@ since the last major version increase
  The last version increases were:
  libavcodec:    2012-01-27
  libavdevice:   2011-04-18
- libavfilter:   2011-04-18
+ libavfilter:   2012-06-22
  libavformat:   2012-01-27
  libavresample: 2012-04-24
 +libpostproc:   2011-04-18
 +libswresample: 2011-09-19
  libswscale:    2011-06-20
  libavutil:     2011-04-18
  
@@@ -649,9 -232,81 +649,79 @@@ front_center.wav -map '[LFE]' lfe.wav -
  side_right.wav
  @end example
  
 -avconv -i in.mov -filter 'channelmap=map=DL-FL\,DR-FR' out.wav
+ @section channelmap
+ Remap input channels to new locations.
+ This filter accepts the following named parameters:
+ @table @option
+ @item channel_layout
+ Channel layout of the output stream.
+ @item map
+ Map channels from input to output. The argument is a comma-separated list of
+ mappings, each in the @code{@var{in_channel}-@var{out_channel}} or
+ @var{in_channel} form. @var{in_channel} can be either the name of the input
+ channel (e.g. FL for front left) or its index in the input channel layout.
+ @var{out_channel} is the name of the output channel or its index in the output
+ channel layout. If @var{out_channel} is not given then it is implicitly an
+ index, starting with zero and increasing by one for each mapping.
+ @end table
+ If no mapping is present, the filter will implicitly map input channels to
+ output channels preserving index.
+ For example, assuming a 5.1+downmix input MOV file
+ @example
 -avconv -i in.wav -filter 'channelmap=1\,2\,0\,5\,3\,4:channel_layout=5.1' out.wav
++ffmpeg -i in.mov -filter 'channelmap=map=DL-FL\,DR-FR' out.wav
+ @end example
+ will create an output WAV file tagged as stereo from the downmix channels of
+ the input.
+ To fix a 5.1 WAV improperly encoded in AAC's native channel order
+ @example
 -avconv -i INPUT1 -i INPUT2 -i INPUT3 -filter_complex join=inputs=3 OUTPUT
++ffmpeg -i in.wav -filter 'channelmap=1\,2\,0\,5\,3\,4:channel_layout=5.1' out.wav
+ @end example
+ @section join
+ Join multiple input streams into one multi-channel stream.
+ The filter accepts the following named parameters:
+ @table @option
+ @item inputs
+ Number of input streams. Defaults to 2.
+ @item channel_layout
+ Desired output channel layout. Defaults to stereo.
+ @item map
+ Map channels from inputs to output. The argument is a comma-separated list of
+ mappings, each in the @code{@var{input_idx}.@var{in_channel}-@var{out_channel}}
+ form. @var{input_idx} is the 0-based index of the input stream. @var{in_channel}
+ can be either the name of the input channel (e.g. FR for front left) or its
+ index in the specified input stream. @var{out_channel} is the name of the output
+ channel.
+ @end table
+ The filter will attempt to guess the mappings when those are not specified
+ explicitly. It does so by first trying to find an unused matching input channel
+ and if that fails it picks the first unused input channel.
+ E.g. to join 3 inputs (with properly set channel layouts)
+ @example
 -avconv -i fl -i fr -i fc -i sl -i sr -i lfe -filter_complex
++ffmpeg -i INPUT1 -i INPUT2 -i INPUT3 -filter_complex join=inputs=3 OUTPUT
+ @end example
+ To build a 5.1 output from 6 single-channel streams:
+ @example
++ffmpeg -i fl -i fr -i fc -i sl -i sr -i lfe -filter_complex
+ 'join=inputs=6:channel_layout=5.1:map=0.0-FL\,1.0-FR\,2.0-FC\,3.0-SL\,4.0-SR\,5.0-LFE'
+ out
+ @end example
  @section resample
  Convert the audio sample format, sample rate and channel layout. This filter is
 -not meant to be used directly, it is inserted automatically by libavfilter
 -whenever conversion is needed. Use the @var{aformat} filter to force a specific
 -conversion.
 +not meant to be used directly.
  
  @c man end AUDIO FILTERS
  
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -41,44 -25,23 +41,46 @@@ OBJS = allfilters.
         vf_scale.o                                                       \
         video.o                                                          \
  
 +
 +OBJS-$(CONFIG_AVCODEC)                       += avcodec.o
 +OBJS-$(CONFIG_AVFORMAT)                      += lavfutils.o
 +OBJS-$(CONFIG_SWSCALE)                       += lswsutils.o
 +
 +OBJS-$(CONFIG_ACONVERT_FILTER)               += af_aconvert.o
  OBJS-$(CONFIG_AFIFO_FILTER)                  += fifo.o
  OBJS-$(CONFIG_AFORMAT_FILTER)                += af_aformat.o
 +OBJS-$(CONFIG_AMERGE_FILTER)                 += af_amerge.o
  OBJS-$(CONFIG_AMIX_FILTER)                   += af_amix.o
  OBJS-$(CONFIG_ANULL_FILTER)                  += af_anull.o
 +OBJS-$(CONFIG_ARESAMPLE_FILTER)              += af_aresample.o
 +OBJS-$(CONFIG_ASETNSAMPLES_FILTER)           += af_asetnsamples.o
 +OBJS-$(CONFIG_ASHOWINFO_FILTER)              += af_ashowinfo.o
  OBJS-$(CONFIG_ASPLIT_FILTER)                 += split.o
 +OBJS-$(CONFIG_ASTREAMSYNC_FILTER)            += af_astreamsync.o
  OBJS-$(CONFIG_ASYNCTS_FILTER)                += af_asyncts.o
 +OBJS-$(CONFIG_ATEMPO_FILTER)                 += af_atempo.o
+ OBJS-$(CONFIG_CHANNELMAP_FILTER)             += af_channelmap.o
  OBJS-$(CONFIG_CHANNELSPLIT_FILTER)           += af_channelsplit.o
 +OBJS-$(CONFIG_EARWAX_FILTER)                 += af_earwax.o
+ OBJS-$(CONFIG_JOIN_FILTER)                   += af_join.o
 +OBJS-$(CONFIG_PAN_FILTER)                    += af_pan.o
  OBJS-$(CONFIG_RESAMPLE_FILTER)               += af_resample.o
 +OBJS-$(CONFIG_SILENCEDETECT_FILTER)          += af_silencedetect.o
 +OBJS-$(CONFIG_VOLUME_FILTER)                 += af_volume.o
  
 +OBJS-$(CONFIG_AEVALSRC_FILTER)               += asrc_aevalsrc.o
 +OBJS-$(CONFIG_AMOVIE_FILTER)                 += src_movie.o
  OBJS-$(CONFIG_ANULLSRC_FILTER)               += asrc_anullsrc.o
  
 +OBJS-$(CONFIG_ABUFFERSINK_FILTER)            += sink_buffer.o
  OBJS-$(CONFIG_ANULLSINK_FILTER)              += asink_anullsink.o
  
 +OBJS-$(CONFIG_ASS_FILTER)                    += vf_ass.o
 +OBJS-$(CONFIG_BBOX_FILTER)                   += bbox.o vf_bbox.o
 +OBJS-$(CONFIG_BLACKDETECT_FILTER)            += vf_blackdetect.o
  OBJS-$(CONFIG_BLACKFRAME_FILTER)             += vf_blackframe.o
  OBJS-$(CONFIG_BOXBLUR_FILTER)                += vf_boxblur.o
 +OBJS-$(CONFIG_COLORMATRIX_FILTER)            += vf_colormatrix.o
  OBJS-$(CONFIG_COPY_FILTER)                   += vf_copy.o
  OBJS-$(CONFIG_CROP_FILTER)                   += vf_crop.o
  OBJS-$(CONFIG_CROPDETECT_FILTER)             += vf_cropdetect.o
index 3cf593b,0000000..53d6b87
mode 100644,000000..100644
--- /dev/null
@@@ -1,171 -1,0 +1,171 @@@
-     ff_formats_ref(avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO),
 +/*
 + * 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/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, void *opaque)
 +{
 +    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(avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO),
++    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;
 +}
 +
 +static void 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);
 +
 +    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;
 +
 +    ff_filter_samples(outlink, outsamplesref);
 +    avfilter_unref_buffer(insamplesref);
 +}
 +
 +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}},
 +};
Simple merge
index e71c55f,0000000..f90412c
mode 100644,000000..100644
--- /dev/null
@@@ -1,336 -1,0 +1,336 @@@
-             if ((ret = avfilter_request_frame(ctx->inputs[i])) < 0)
 +/*
 + * 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/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 "
 +                   "(%"PRIi64" for in%d vs %"PRIi64")\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;
 +    }
 +}
 +
 +static void 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)
 +        return;
 +
 +    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;
 +            }
 +        }
 +    }
 +    ff_filter_samples(ctx->outputs[0], outbuf);
 +}
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
 +{
 +    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 }
 +    },
 +};
@@@ -32,13 -31,12 +32,12 @@@ AVFilter avfilter_af_anull = 
  
      .priv_size = 0,
  
 -    .inputs    = (AVFilterPad[]) {{ .name             = "default",
 +    .inputs    = (const AVFilterPad[]) {{ .name       = "default",
                                      .type             = AVMEDIA_TYPE_AUDIO,
-                                     .get_audio_buffer = ff_null_get_audio_buffer,
-                                     .filter_samples   = ff_null_filter_samples },
+                                     .get_audio_buffer = ff_null_get_audio_buffer, },
                                    { .name = NULL}},
  
 -    .outputs   = (AVFilterPad[]) {{ .name             = "default",
 +    .outputs   = (const AVFilterPad[]) {{ .name       = "default",
                                      .type             = AVMEDIA_TYPE_AUDIO, },
                                    { .name = NULL}},
  };
index 81f326f,0000000..fdbc828
mode 100644,000000..100644
--- /dev/null
@@@ -1,264 -1,0 +1,264 @@@
-         out_formats = avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO);
 +/*
 + * 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/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, void *opaque)
 +{
 +    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
-         ret = avfilter_request_frame(ctx->inputs[0]);
++        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:%"PRId64"Hz -> chl:%s fmt:%s r:%"PRId64"Hz\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;
 +}
 +
 +static void 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);
 +
 +
 +    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);
 +        return;
 +    }
 +
 +    outsamplesref->audio->sample_rate = outlink->sample_rate;
 +    outsamplesref->audio->nb_samples  = n_out;
 +
 +    ff_filter_samples(outlink, outsamplesref);
 +    aresample->req_fullfilled= 1;
 +    avfilter_unref_buffer(insamplesref);
 +}
 +
 +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 b373fc2,0000000..d371c98
mode 100644,000000..100644
--- /dev/null
@@@ -1,203 -1,0 +1,203 @@@
-         ret = avfilter_request_frame(inlink);
 +/*
 + * 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/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, void *opaque)
 +{
 +    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;
 +}
 +
 +static void 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;
 +        }
 +    }
 +    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);
 +}
 +
 +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 18a2fe6,0000000..ff3f3c2
mode 100644,000000..100644
--- /dev/null
@@@ -1,210 -1,0 +1,210 @@@
-             avfilter_request_frame(ctx->inputs[as->next_out]);
 +/*
 + * 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, void *opaque)
 +{
 +    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;
 +}
 +
 +static void 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];
 +
 +    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;
 +    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]--;
 +}
 +
 +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 void 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);
 +}
 +
 +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 }
 +    },
 +};
index 92390cf,0000000..4458439
mode 100644,000000..100644
--- /dev/null
@@@ -1,1160 -1,0 +1,1160 @@@
-         ret = avfilter_request_frame(ctx->inputs[0]);
 +/*
 + * 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/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, void *opaque)
 +{
 +    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 void 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);
 +}
 +
 +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}
 +    },
 +};
index 0000000,14c2c0c..fe766fd
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,402 +1,402 @@@
 - * This file is part of Libav.
+ /*
+  * Copyright (c) 2012 Google, Inc.
+  *
 - * 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
+  */
+ /**
+  * @file
+  * audio channel mapping filter
+  */
+ #include <ctype.h>
+ #include "libavutil/audioconvert.h"
+ #include "libavutil/avstring.h"
+ #include "libavutil/mathematics.h"
+ #include "libavutil/opt.h"
+ #include "libavutil/samplefmt.h"
+ #include "audio.h"
+ #include "avfilter.h"
+ #include "formats.h"
+ #include "internal.h"
+ struct ChannelMap {
+     uint64_t in_channel;
+     uint64_t out_channel;
+     int in_channel_idx;
+     int out_channel_idx;
+ };
+ enum MappingMode {
+     MAP_NONE,
+     MAP_ONE_INT,
+     MAP_ONE_STR,
+     MAP_PAIR_INT_INT,
+     MAP_PAIR_INT_STR,
+     MAP_PAIR_STR_INT,
+     MAP_PAIR_STR_STR
+ };
+ #define MAX_CH 64
+ typedef struct ChannelMapContext {
+     const AVClass *class;
+     AVFilterChannelLayouts *channel_layouts;
+     char *mapping_str;
+     char *channel_layout_str;
+     uint64_t output_layout;
+     struct ChannelMap map[MAX_CH];
+     int nch;
+     enum MappingMode mode;
+ } ChannelMapContext;
+ #define OFFSET(x) offsetof(ChannelMapContext, x)
+ #define A AV_OPT_FLAG_AUDIO_PARAM
+ static const AVOption options[] = {
+     { "map", "A comma-separated list of input channel numbers in output order.",
+           OFFSET(mapping_str),        AV_OPT_TYPE_STRING, .flags = A },
+     { "channel_layout", "Output channel layout.",
+           OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A },
+     { NULL },
+ };
+ static const AVClass channelmap_class = {
+     .class_name = "channel map filter",
+     .item_name  = av_default_item_name,
+     .option     = options,
+     .version    = LIBAVUTIL_VERSION_INT,
+ };
+ static char* split(char *message, char delim) {
+     char *next = strchr(message, delim);
+     if (next)
+       *next++ = '\0';
+     return next;
+ }
+ static int get_channel_idx(char **map, int *ch, char delim, int max_ch)
+ {
+     char *next = split(*map, delim);
+     int len;
+     int n = 0;
+     if (!next && delim == '-')
+         return AVERROR(EINVAL);
+     len = strlen(*map);
+     sscanf(*map, "%d%n", ch, &n);
+     if (n != len)
+         return AVERROR(EINVAL);
+     if (*ch < 0 || *ch > max_ch)
+         return AVERROR(EINVAL);
+     *map = next;
+     return 0;
+ }
+ static int get_channel(char **map, uint64_t *ch, char delim)
+ {
+     char *next = split(*map, delim);
+     if (!next && delim == '-')
+         return AVERROR(EINVAL);
+     *ch = av_get_channel_layout(*map);
+     if (av_get_channel_layout_nb_channels(*ch) != 1)
+         return AVERROR(EINVAL);
+     *map = next;
+     return 0;
+ }
+ static av_cold int channelmap_init(AVFilterContext *ctx, const char *args,
+                                    void *opaque)
+ {
+     ChannelMapContext *s = ctx->priv;
+     int ret;
+     char *mapping;
+     enum mode;
+     int map_entries = 0;
+     char buf[256];
+     enum MappingMode mode;
+     uint64_t out_ch_mask = 0;
+     int i;
+     if (!args) {
+         av_log(ctx, AV_LOG_ERROR, "No parameters supplied.\n");
+         return AVERROR(EINVAL);
+     }
+     s->class = &channelmap_class;
+     av_opt_set_defaults(s);
+     if ((ret = av_set_options_string(s, args, "=", ":")) < 0) {
+         av_log(ctx, AV_LOG_ERROR, "Error parsing options string '%s'.\n", args);
+         return ret;
+     }
+     mapping = s->mapping_str;
+     if (!mapping) {
+         mode = MAP_NONE;
+     } else {
+         char *dash = strchr(mapping, '-');
+         if (!dash) {  // short mapping
+             if (isdigit(*mapping))
+                 mode = MAP_ONE_INT;
+             else
+                 mode = MAP_ONE_STR;
+         } else if (isdigit(*mapping)) {
+             if (isdigit(*(dash+1)))
+                 mode = MAP_PAIR_INT_INT;
+             else
+                 mode = MAP_PAIR_INT_STR;
+         } else {
+             if (isdigit(*(dash+1)))
+                 mode = MAP_PAIR_STR_INT;
+             else
+                 mode = MAP_PAIR_STR_STR;
+         }
+     }
+     if (mode != MAP_NONE) {
+         char *comma = mapping;
+         map_entries = 1;
+         while ((comma = strchr(comma, ','))) {
+             if (*++comma)  // Allow trailing comma
+                 map_entries++;
+         }
+     }
+     if (map_entries > MAX_CH) {
+         av_log(ctx, AV_LOG_ERROR, "Too many channels mapped: '%d'.\n", map_entries);
+         ret = AVERROR(EINVAL);
+         goto fail;
+     }
+     for (i = 0; i < map_entries; i++) {
+         int in_ch_idx = -1, out_ch_idx = -1;
+         uint64_t in_ch = 0, out_ch = 0;
+         static const char err[] = "Failed to parse channel map\n";
+         switch (mode) {
+         case MAP_ONE_INT:
+             if (get_channel_idx(&mapping, &in_ch_idx, ',', MAX_CH) < 0) {
+                 ret = AVERROR(EINVAL);
+                 av_log(ctx, AV_LOG_ERROR, err);
+                 goto fail;
+             }
+             s->map[i].in_channel_idx  = in_ch_idx;
+             s->map[i].out_channel_idx = i;
+             break;
+         case MAP_ONE_STR:
+             if (!get_channel(&mapping, &in_ch, ',')) {
+                 av_log(ctx, AV_LOG_ERROR, err);
+                 ret = AVERROR(EINVAL);
+                 goto fail;
+             }
+             s->map[i].in_channel      = in_ch;
+             s->map[i].out_channel_idx = i;
+             break;
+         case MAP_PAIR_INT_INT:
+             if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 ||
+                 get_channel_idx(&mapping, &out_ch_idx, ',', MAX_CH) < 0) {
+                 av_log(ctx, AV_LOG_ERROR, err);
+                 ret = AVERROR(EINVAL);
+                 goto fail;
+             }
+             s->map[i].in_channel_idx  = in_ch_idx;
+             s->map[i].out_channel_idx = out_ch_idx;
+             break;
+         case MAP_PAIR_INT_STR:
+             if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 ||
+                 get_channel(&mapping, &out_ch, ',') < 0 ||
+                 out_ch & out_ch_mask) {
+                 av_log(ctx, AV_LOG_ERROR, err);
+                 ret = AVERROR(EINVAL);
+                 goto fail;
+             }
+             s->map[i].in_channel_idx  = in_ch_idx;
+             s->map[i].out_channel     = out_ch;
+             out_ch_mask |= out_ch;
+             break;
+         case MAP_PAIR_STR_INT:
+             if (get_channel(&mapping, &in_ch, '-') < 0 ||
+                 get_channel_idx(&mapping, &out_ch_idx, ',', MAX_CH) < 0) {
+                 av_log(ctx, AV_LOG_ERROR, err);
+                 ret = AVERROR(EINVAL);
+                 goto fail;
+             }
+             s->map[i].in_channel      = in_ch;
+             s->map[i].out_channel_idx = out_ch_idx;
+             break;
+         case MAP_PAIR_STR_STR:
+             if (get_channel(&mapping, &in_ch, '-') < 0 ||
+                 get_channel(&mapping, &out_ch, ',') < 0 ||
+                 out_ch & out_ch_mask) {
+                 av_log(ctx, AV_LOG_ERROR, err);
+                 ret = AVERROR(EINVAL);
+                 goto fail;
+             }
+             s->map[i].in_channel = in_ch;
+             s->map[i].out_channel = out_ch;
+             out_ch_mask |= out_ch;
+             break;
+         }
+     }
+     s->mode          = mode;
+     s->nch           = map_entries;
+     s->output_layout = out_ch_mask ? out_ch_mask :
+                        av_get_default_channel_layout(map_entries);
+     if (s->channel_layout_str) {
+         uint64_t fmt;
+         if ((fmt = av_get_channel_layout(s->channel_layout_str)) == 0) {
+             av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: '%s'.\n",
+                    s->channel_layout_str);
+             ret = AVERROR(EINVAL);
+             goto fail;
+         }
+         if (mode == MAP_NONE) {
+             int i;
+             s->nch = av_get_channel_layout_nb_channels(fmt);
+             for (i = 0; i < s->nch; i++) {
+                 s->map[i].in_channel_idx  = i;
+                 s->map[i].out_channel_idx = i;
+             }
+         } else if (out_ch_mask && out_ch_mask != fmt) {
+             av_get_channel_layout_string(buf, sizeof(buf), 0, out_ch_mask);
+             av_log(ctx, AV_LOG_ERROR,
+                    "Output channel layout '%s' does not match the list of channel mapped: '%s'.\n",
+                    s->channel_layout_str, buf);
+             ret = AVERROR(EINVAL);
+             goto fail;
+         } else if (s->nch != av_get_channel_layout_nb_channels(fmt)) {
+             av_log(ctx, AV_LOG_ERROR,
+                    "Output channel layout %s does not match the number of channels mapped %d.\n",
+                    s->channel_layout_str, s->nch);
+             ret = AVERROR(EINVAL);
+             goto fail;
+         }
+         s->output_layout = fmt;
+     }
+     ff_add_channel_layout(&s->channel_layouts, s->output_layout);
+     if (mode == MAP_PAIR_INT_STR || mode == MAP_PAIR_STR_STR) {
+         for (i = 0; i < s->nch; i++) {
+             s->map[i].out_channel_idx = av_get_channel_layout_channel_index(
+                 s->output_layout, s->map[i].out_channel);
+         }
+     }
+ fail:
+     av_opt_free(s);
+     return ret;
+ }
+ static int channelmap_query_formats(AVFilterContext *ctx)
+ {
+     ChannelMapContext *s = ctx->priv;
+     ff_set_common_formats(ctx, ff_planar_sample_fmts());
+     ff_set_common_samplerates(ctx, ff_all_samplerates());
+     ff_channel_layouts_ref(ff_all_channel_layouts(), &ctx->inputs[0]->out_channel_layouts);
+     ff_channel_layouts_ref(s->channel_layouts,       &ctx->outputs[0]->in_channel_layouts);
+     return 0;
+ }
+ static void channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
+ {
+     AVFilterContext  *ctx = inlink->dst;
+     AVFilterLink *outlink = ctx->outputs[0];
+     const ChannelMapContext *s = ctx->priv;
+     const int nch_in = av_get_channel_layout_nb_channels(inlink->channel_layout);
+     const int nch_out = s->nch;
+     int ch;
+     uint8_t *source_planes[MAX_CH];
+     memcpy(source_planes, buf->extended_data,
+            nch_in * sizeof(source_planes[0]));
+     if (nch_out > nch_in) {
+         if (nch_out > FF_ARRAY_ELEMS(buf->data)) {
+             uint8_t **new_extended_data =
+                 av_mallocz(nch_out * sizeof(*buf->extended_data));
+             if (!new_extended_data)
+                 return;
+             if (buf->extended_data == buf->data) {
+                 buf->extended_data = new_extended_data;
+             } else {
+                 buf->extended_data = new_extended_data;
+                 av_free(buf->extended_data);
+             }
+         } else if (buf->extended_data != buf->data) {
+             av_free(buf->extended_data);
+             buf->extended_data = buf->data;
+         }
+     }
+     for (ch = 0; ch < nch_out; ch++) {
+         buf->extended_data[s->map[ch].out_channel_idx] =
+             source_planes[s->map[ch].in_channel_idx];
+     }
+     if (buf->data != buf->extended_data)
+         memcpy(buf->data, buf->extended_data,
+            FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0]));
+     ff_filter_samples(outlink, buf);
+ }
+ static int channelmap_config_input(AVFilterLink *inlink)
+ {
+     AVFilterContext *ctx = inlink->dst;
+     ChannelMapContext *s = ctx->priv;
+     int i, err = 0;
+     const char *channel_name;
+     char layout_name[256];
+     if (s->mode == MAP_PAIR_STR_INT || s->mode == MAP_PAIR_STR_STR) {
+         for (i = 0; i < s->nch; i++) {
+             s->map[i].in_channel_idx = av_get_channel_layout_channel_index(
+                 inlink->channel_layout, s->map[i].in_channel);
+             if (s->map[i].in_channel_idx < 0) {
+                 channel_name = av_get_channel_name(s->map[i].in_channel);
+                 av_get_channel_layout_string(layout_name, sizeof(layout_name),
+                                              0, inlink->channel_layout);
+                 av_log(ctx, AV_LOG_ERROR,
+                        "input channel '%s' not available from input layout '%s'\n",
+                        channel_name, layout_name);
+                 err = AVERROR(EINVAL);
+             }
+         }
+     }
+     return err;
+ }
+ AVFilter avfilter_af_channelmap = {
+     .name          = "channelmap",
+     .description   = NULL_IF_CONFIG_SMALL("Remap audio channels."),
+     .init          = channelmap_init,
+     .query_formats = channelmap_query_formats,
+     .priv_size     = sizeof(ChannelMapContext),
+     .inputs        = (AVFilterPad[]) {{ .name            = "default",
+                                         .type            = AVMEDIA_TYPE_AUDIO,
+                                         .filter_samples  = channelmap_filter_samples,
+                                         .config_props    = channelmap_config_input },
+                                       { .name = NULL }},
+     .outputs       = (AVFilterPad[]) {{ .name            = "default",
+                                         .type            = AVMEDIA_TYPE_AUDIO },
+                                       { .name = NULL }},
+ };
index aed59cd,0000000..cda40a7
mode 100644,000000..100644
--- /dev/null
@@@ -1,387 -1,0 +1,387 @@@
-     ff_set_common_formats(ctx, avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO));
 +/*
 + * 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/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, void *opaque)
 +{
 +    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;
 +}
 +
 +static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 +{
 +    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;
 +
 +    ff_filter_samples(outlink, outsamples);
 +    avfilter_unref_buffer(insamples);
 +}
 +
 +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}
 +    },
 +};
@@@ -34,39 -34,23 +34,41 @@@ void avfilter_register_all(void
          return;
      initialized = 1;
  
 +    REGISTER_FILTER (ACONVERT,    aconvert,    af);
      REGISTER_FILTER (AFIFO,       afifo,       af);
      REGISTER_FILTER (AFORMAT,     aformat,     af);
 +    REGISTER_FILTER (AMERGE,      amerge,      af);
      REGISTER_FILTER (AMIX,        amix,        af);
      REGISTER_FILTER (ANULL,       anull,       af);
 +    REGISTER_FILTER (ARESAMPLE,   aresample,   af);
 +    REGISTER_FILTER (ASETNSAMPLES, asetnsamples, af);
 +    REGISTER_FILTER (ASHOWINFO,   ashowinfo,   af);
      REGISTER_FILTER (ASPLIT,      asplit,      af);
 +    REGISTER_FILTER (ASTREAMSYNC, astreamsync, af);
      REGISTER_FILTER (ASYNCTS,     asyncts,     af);
 +    REGISTER_FILTER (ATEMPO,      atempo,      af);
+     REGISTER_FILTER (CHANNELMAP,  channelmap,  af);
      REGISTER_FILTER (CHANNELSPLIT,channelsplit,af);
 +    REGISTER_FILTER (EARWAX,      earwax,      af);
+     REGISTER_FILTER (JOIN,        join,        af);
 +    REGISTER_FILTER (PAN,         pan,         af);
 +    REGISTER_FILTER (SILENCEDETECT, silencedetect, af);
 +    REGISTER_FILTER (VOLUME,      volume,      af);
      REGISTER_FILTER (RESAMPLE,    resample,    af);
  
 +    REGISTER_FILTER (AEVALSRC,    aevalsrc,    asrc);
 +    REGISTER_FILTER (AMOVIE,      amovie,      asrc);
      REGISTER_FILTER (ANULLSRC,    anullsrc,    asrc);
  
 +    REGISTER_FILTER (ABUFFERSINK, abuffersink, asink);
      REGISTER_FILTER (ANULLSINK,   anullsink,   asink);
  
 +    REGISTER_FILTER (ASS,         ass,         vf);
 +    REGISTER_FILTER (BBOX,        bbox,        vf);
 +    REGISTER_FILTER (BLACKDETECT, blackdetect, vf);
      REGISTER_FILTER (BLACKFRAME,  blackframe,  vf);
      REGISTER_FILTER (BOXBLUR,     boxblur,     vf);
 +    REGISTER_FILTER (COLORMATRIX, colormatrix, vf);
      REGISTER_FILTER (COPY,        copy,        vf);
      REGISTER_FILTER (CROP,        crop,        vf);
      REGISTER_FILTER (CROPDETECT,  cropdetect,  vf);
@@@ -180,13 -156,12 +160,13 @@@ void ff_filter_samples(AVFilterLink *li
  {
      void (*filter_samples)(AVFilterLink *, AVFilterBufferRef *);
      AVFilterPad *dst = link->dstpad;
 +    int64_t pts;
      AVFilterBufferRef *buf_out;
  
 -    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 = ff_default_filter_samples;
+         filter_samples = default_filter_samples;
  
      /* prepare to copy the samples if the buffer has insufficient permissions */
      if ((dst->min_perms & samplesref->perms) != dst->min_perms ||
Simple merge
index 121f785,0000000..f6fa454
mode 100644,000000..100644
--- /dev/null
@@@ -1,257 -1,0 +1,257 @@@
-         ret = avfilter_request_frame(inlink);
 +/*
 + * 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, void *opaque)
 +{
 +    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 void 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);
 +}
 +
 +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 }
 +    },
 +};
@@@ -211,55 -198,8 +211,55 @@@ AVFilterBufferRef *avfilter_ref_buffer(
   */
  void avfilter_unref_buffer(AVFilterBufferRef *ref);
  
- #if FF_API_FILTERS_PUBLIC
 +/**
 + * Remove a reference to a buffer and set the pointer to NULL.
 + * If this is the last reference to the buffer, the buffer itself
 + * is also automatically freed.
 + *
 + * @param ref pointer to the buffer reference
 + */
 +void avfilter_unref_bufferp(AVFilterBufferRef **ref);
 +
+ #if FF_API_FILTERS_PUBLIC
  /**
 + * A list of supported formats for one end of a filter link. This is used
 + * during the format negotiation process to try to pick the best format to
 + * use to minimize the number of necessary conversions. Each filter gives a
 + * list of the formats supported by each input and output pad. The list
 + * given for each pad need not be distinct - they may be references to the
 + * same list of formats, as is often the case when a filter supports multiple
 + * formats, but will always output the same format as it is given in input.
 + *
 + * In this way, a list of possible input formats and a list of possible
 + * output formats are associated with each link. When a set of formats is
 + * negotiated over a link, the input and output lists are merged to form a
 + * new list containing only the common elements of each list. In the case
 + * that there were no common elements, a format conversion is necessary.
 + * Otherwise, the lists are merged, and all other links which reference
 + * either of the format lists involved in the merge are also affected.
 + *
 + * For example, consider the filter chain:
 + * filter (a) --> (b) filter (b) --> (c) filter
 + *
 + * where the letters in parenthesis indicate a list of formats supported on
 + * the input or output of the link. Suppose the lists are as follows:
 + * (a) = {A, B}
 + * (b) = {A, B, C}
 + * (c) = {B, C}
 + *
 + * First, the first link's lists are merged, yielding:
 + * filter (a) --> (a) filter (a) --> (c) filter
 + *
 + * Notice that format list (b) now refers to the same list as filter list (a).
 + * Next, the lists for the second link are merged, yielding:
 + * filter (a) --> (a) filter (a) --> (a) filter
 + *
 + * where (a) = {B}.
 + *
 + * Unfortunately, when the format lists at the two ends of a link are merged,
 + * we must ensure that all links which reference either pre-merge format list
 + * get updated as well. Therefore, we have the format list structure store a
 + * pointer to each of the pointers to itself.
   * @addtogroup lavfi_deprecated
   * @deprecated Those functions are only useful inside filters and
   * user filters are not supported at this point.
@@@ -273,71 -213,14 +273,71 @@@ struct AVFilterFormats 
      struct AVFilterFormats ***refs; ///< references to this list
  };
  
 +/**
 + * Create a list of supported formats. This is intended for use in
 + * AVFilter->query_formats().
 + *
 + * @param fmts list of media formats, terminated by -1. If NULL an
 + *        empty list is created.
 + * @return the format list, with no existing references
 + */
  attribute_deprecated
  AVFilterFormats *avfilter_make_format_list(const int *fmts);
-  * @deprecated Use avfilter_make_all_formats() instead.
 +
 +/**
 + * Add fmt to the list of media formats contained in *avff.
 + * If *avff is NULL the function allocates the filter formats struct
 + * and puts its pointer in *avff.
 + *
 + * @return a non negative value in case of success, or a negative
 + * value corresponding to an AVERROR code in case of error
++ * @deprecated Use ff_all_formats() instead.
 + */
  attribute_deprecated
 -int avfilter_add_format(AVFilterFormats **avff, int fmt);
 +int avfilter_add_format(AVFilterFormats **avff, int64_t fmt);
  attribute_deprecated
  AVFilterFormats *avfilter_all_formats(enum AVMediaType type);
 +
 +/**
 + * Return a list of all formats supported by FFmpeg for the given media type.
 + */
 +AVFilterFormats *avfilter_make_all_formats(enum AVMediaType type);
 +
 +/**
 + * A list of all channel layouts supported by libavfilter.
 + */
 +extern const int64_t avfilter_all_channel_layouts[];
 +
 +#if FF_API_PACKING
 +/**
 + * Return a list of all audio packing formats.
 + */
 +AVFilterFormats *avfilter_make_all_packing_formats(void);
 +#endif
 +
 +/**
 + * Return a format list which contains the intersection of the formats of
 + * a and b. Also, all the references of a, all the references of b, and
 + * a and b themselves will be deallocated.
 + *
 + * If a and b do not share any common formats, neither is modified, and NULL
 + * is returned.
 + */
  attribute_deprecated
  AVFilterFormats *avfilter_merge_formats(AVFilterFormats *a, AVFilterFormats *b);
 +
 +/**
 + * Add *ref as a new reference to formats.
 + * That is the pointers will point like in the ASCII art below:
 + *   ________
 + *  |formats |<--------.
 + *  |  ____  |     ____|___________________
 + *  | |refs| |    |  __|_
 + *  | |* * | |    | |  | |  AVFilterLink
 + *  | |* *--------->|*ref|
 + *  | |____| |    | |____|
 + *  |________|    |________________________
 + */
  attribute_deprecated
  void avfilter_formats_ref(AVFilterFormats *formats, AVFilterFormats **ref);
  attribute_deprecated
@@@ -479,8 -343,6 +479,8 @@@ struct AVFilterPad 
       * Frame request callback. A call to this should result in at least one
       * frame being output over the given link. This should return zero on
       * success, and another value on error.
-      * See avfilter_request_frame() for the error codes with a specific
++     * See ff_request_frame() for the error codes with a specific
 +     * meaning.
       *
       * Output pads only.
       */
@@@ -529,6 -396,6 +537,10 @@@ const char *avfilter_pad_get_name(AVFil
   */
  enum AVMediaType avfilter_pad_get_type(AVFilterPad *pads, int pad_idx);
  
++/** default handler for end_frame() for video inputs */
++attribute_deprecated
++void avfilter_default_end_frame(AVFilterLink *link);
++
  #if FF_API_FILTERS_PUBLIC
  /** default handler for start_frame() for video inputs */
  attribute_deprecated
@@@ -538,10 -405,16 +550,6 @@@ void avfilter_default_start_frame(AVFil
  attribute_deprecated
  void avfilter_default_draw_slice(AVFilterLink *link, int y, int h, int slice_dir);
  
--/** default handler for end_frame() for video inputs */
--attribute_deprecated
--void avfilter_default_end_frame(AVFilterLink *link);
 -
 -#if FF_API_DEFAULT_CONFIG_OUTPUT_LINK
 -/** default handler for config_props() for audio/video outputs */
 -attribute_deprecated
 -int avfilter_default_config_output_link(AVFilterLink *link);
 -#endif
--
  /** default handler for get_video_buffer() for video inputs */
  attribute_deprecated
  AVFilterBufferRef *avfilter_default_get_video_buffer(AVFilterLink *link,
@@@ -756,36 -596,14 +764,44 @@@ struct AVFilterLink 
      struct AVFilterChannelLayouts  *in_channel_layouts;
      struct AVFilterChannelLayouts *out_channel_layouts;
  
+     /**
+      * Audio only, the destination filter sets this to a non-zero value to
+      * request that buffers with the given number of samples should be sent to
+      * it. AVFilterPad.needs_fifo must also be set on the corresponding input
+      * pad.
+      * Last buffer before EOF will be padded with silence.
+      */
+     int request_samples;
++
 +    struct AVFilterPool *pool;
 +
 +    /**
 +     * Graph the filter belongs to.
 +     */
 +    struct AVFilterGraph *graph;
 +
 +    /**
 +     * Current timestamp of the link, as defined by the most recent
 +     * frame(s), in AV_TIME_BASE units.
 +     */
 +    int64_t current_pts;
 +
 +    /**
 +     * Index in the age array.
 +     */
 +    int age_index;
 +
 +    /**
 +     * Frame rate of the stream on the link, or 1/0 if unknown;
 +     * if left to 0/0, will be automatically be copied from the first input
 +     * of the source filter if it exists.
 +     *
 +     * Sources should set it to the best estimation of the real frame rate.
 +     * Filters should update it if necessary depending on their function.
 +     * Sinks can use it to set a default output frame rate.
 +     * It is similar to the r_frae_rate field in AVStream.
 +     */
 +    AVRational frame_rate;
  };
  
  /**
@@@ -174,89 -164,6 +174,89 @@@ AVFilterContext *avfilter_graph_get_fil
      return NULL;
  }
  
-     formats = avfilter_make_all_formats(type);
 +static int filter_query_formats(AVFilterContext *ctx)
 +{
 +    int ret;
 +    AVFilterFormats *formats;
 +    AVFilterChannelLayouts *chlayouts;
 +    AVFilterFormats *samplerates;
 +    enum AVMediaType type = ctx->inputs  && ctx->inputs [0] ? ctx->inputs [0]->type :
 +                            ctx->outputs && ctx->outputs[0] ? ctx->outputs[0]->type :
 +                            AVMEDIA_TYPE_VIDEO;
 +
 +    if ((ret = ctx->filter->query_formats(ctx)) < 0)
 +        return ret;
 +
++    formats = ff_all_formats(type);
 +    if (!formats)
 +        return AVERROR(ENOMEM);
 +    ff_set_common_formats(ctx, formats);
 +    if (type == AVMEDIA_TYPE_AUDIO) {
 +        samplerates = ff_all_samplerates();
 +        if (!samplerates)
 +            return AVERROR(ENOMEM);
 +        ff_set_common_samplerates(ctx, samplerates);
 +        chlayouts = ff_all_channel_layouts();
 +        if (!chlayouts)
 +            return AVERROR(ENOMEM);
 +        ff_set_common_channel_layouts(ctx, chlayouts);
 +    }
 +    return 0;
 +}
 +
 +static int insert_conv_filter(AVFilterGraph *graph, AVFilterLink *link,
 +                              const char *filt_name, const char *filt_args)
 +{
 +    static int auto_count = 0, ret;
 +    char inst_name[32];
 +    AVFilterContext *filt_ctx;
 +
 +    if (graph->disable_auto_convert) {
 +        av_log(NULL, AV_LOG_ERROR,
 +               "The filters '%s' and '%s' do not have a common format "
 +               "and automatic conversion is disabled.\n",
 +               link->src->name, link->dst->name);
 +        return AVERROR(EINVAL);
 +    }
 +
 +    snprintf(inst_name, sizeof(inst_name), "auto-inserted %s %d",
 +            filt_name, auto_count++);
 +
 +    if ((ret = avfilter_graph_create_filter(&filt_ctx,
 +                                            avfilter_get_by_name(filt_name),
 +                                            inst_name, filt_args, NULL, graph)) < 0)
 +        return ret;
 +    if ((ret = avfilter_insert_filter(link, filt_ctx, 0, 0)) < 0)
 +        return ret;
 +
 +    filter_query_formats(filt_ctx);
 +
 +    if ( ((link = filt_ctx-> inputs[0]) &&
 +           !ff_merge_formats(link->in_formats, link->out_formats)) ||
 +         ((link = filt_ctx->outputs[0]) &&
 +           !ff_merge_formats(link->in_formats, link->out_formats))
 +       ) {
 +        av_log(NULL, AV_LOG_ERROR,
 +               "Impossible to convert between the formats supported by the filter "
 +               "'%s' and the filter '%s'\n", link->src->name, link->dst->name);
 +        return AVERROR(EINVAL);
 +    }
 +
 +    if (link->type == AVMEDIA_TYPE_AUDIO &&
 +         (((link = filt_ctx-> inputs[0]) &&
 +           !ff_merge_channel_layouts(link->in_channel_layouts, link->out_channel_layouts)) ||
 +         ((link = filt_ctx->outputs[0]) &&
 +           !ff_merge_channel_layouts(link->in_channel_layouts, link->out_channel_layouts)))
 +       ) {
 +        av_log(NULL, AV_LOG_ERROR,
 +               "Impossible to convert between the channel layouts formats supported by the filter "
 +               "'%s' and the filter '%s'\n", link->src->name, link->dst->name);
 +        return AVERROR(EINVAL);
 +    }
 +
 +    return 0;
 +}
 +
  static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
  {
      int i, j, ret;
@@@ -773,48 -591,44 +773,86 @@@ static int graph_config_formats(AVFilte
      return 0;
  }
  
 +static int ff_avfilter_graph_config_pointers(AVFilterGraph *graph,
 +                                             AVClass *log_ctx)
 +{
 +    unsigned i, j;
 +    int sink_links_count = 0, n = 0;
 +    AVFilterContext *f;
 +    AVFilterLink **sinks;
 +
 +    for (i = 0; i < graph->filter_count; i++) {
 +        f = graph->filters[i];
 +        for (j = 0; j < f->nb_inputs; j++) {
 +            f->inputs[j]->graph     = graph;
 +            f->inputs[j]->age_index = -1;
 +        }
 +        for (j = 0; j < f->nb_outputs; j++) {
 +            f->outputs[j]->graph    = graph;
 +            f->outputs[j]->age_index= -1;
 +        }
 +        if (!f->nb_outputs) {
 +            if (f->nb_inputs > INT_MAX - sink_links_count)
 +                return AVERROR(EINVAL);
 +            sink_links_count += f->nb_inputs;
 +        }
 +    }
 +    sinks = av_calloc(sink_links_count, sizeof(*sinks));
 +    if (!sinks)
 +        return AVERROR(ENOMEM);
 +    for (i = 0; i < graph->filter_count; i++) {
 +        f = graph->filters[i];
 +        if (!f->nb_outputs) {
 +            for (j = 0; j < f->nb_inputs; j++) {
 +                sinks[n] = f->inputs[j];
 +                f->inputs[j]->age_index = n++;
 +            }
 +        }
 +    }
 +    av_assert0(n == sink_links_count);
 +    graph->sink_links       = sinks;
 +    graph->sink_links_count = sink_links_count;
 +    return 0;
 +}
 +
+ static int graph_insert_fifos(AVFilterGraph *graph, AVClass *log_ctx)
+ {
+     AVFilterContext *f;
+     int i, j, ret;
+     int fifo_count = 0;
+     for (i = 0; i < graph->filter_count; i++) {
+         f = graph->filters[i];
+         for (j = 0; j < f->nb_inputs; j++) {
+             AVFilterLink *link = f->inputs[j];
+             AVFilterContext *fifo_ctx;
+             AVFilter *fifo;
+             char name[32];
+             if (!link->dstpad->needs_fifo)
+                 continue;
+             fifo = f->inputs[j]->type == AVMEDIA_TYPE_VIDEO ?
+                    avfilter_get_by_name("fifo") :
+                    avfilter_get_by_name("afifo");
+             snprintf(name, sizeof(name), "auto-inserted fifo %d", fifo_count++);
+             ret = avfilter_graph_create_filter(&fifo_ctx, fifo, name, NULL,
+                                                NULL, graph);
+             if (ret < 0)
+                 return ret;
+             ret = avfilter_insert_filter(link, fifo_ctx, 0, 0);
+             if (ret < 0)
+                 return ret;
+         }
+     }
+     return 0;
+ }
  int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx)
  {
      int ret;
@@@ -888,65 -644,3 +928,65 @@@ int avfilter_graph_queue_command(AVFilt
  
      return 0;
  }
-         int r = avfilter_request_frame(oldest);
 +
 +static void heap_bubble_up(AVFilterGraph *graph,
 +                           AVFilterLink *link, int index)
 +{
 +    AVFilterLink **links = graph->sink_links;
 +
 +    while (index) {
 +        int parent = (index - 1) >> 1;
 +        if (links[parent]->current_pts >= link->current_pts)
 +            break;
 +        links[index] = links[parent];
 +        links[index]->age_index = index;
 +        index = parent;
 +    }
 +    links[index] = link;
 +    link->age_index = index;
 +}
 +
 +static void heap_bubble_down(AVFilterGraph *graph,
 +                             AVFilterLink *link, int index)
 +{
 +    AVFilterLink **links = graph->sink_links;
 +
 +    while (1) {
 +        int child = 2 * index + 1;
 +        if (child >= graph->sink_links_count)
 +            break;
 +        if (child + 1 < graph->sink_links_count &&
 +            links[child + 1]->current_pts < links[child]->current_pts)
 +            child++;
 +        if (link->current_pts < links[child]->current_pts)
 +            break;
 +        links[index] = links[child];
 +        links[index]->age_index = index;
 +        index = child;
 +    }
 +    links[index] = link;
 +    link->age_index = index;
 +}
 +
 +void ff_avfilter_graph_update_heap(AVFilterGraph *graph, AVFilterLink *link)
 +{
 +    heap_bubble_up  (graph, link, link->age_index);
 +    heap_bubble_down(graph, link, link->age_index);
 +}
 +
 +
 +int avfilter_graph_request_oldest(AVFilterGraph *graph)
 +{
 +    while (graph->sink_links_count) {
 +        AVFilterLink *oldest = graph->sink_links[0];
++        int r = ff_request_frame(oldest);
 +        if (r != AVERROR_EOF)
 +            return r;
 +        /* EOF: remove the link from the heap */
 +        if (oldest->age_index < --graph->sink_links_count)
 +            heap_bubble_down(graph, graph->sink_links[graph->sink_links_count],
 +                             oldest->age_index);
 +        oldest->age_index = -1;
 +    }
 +    return AVERROR_EOF;
 +}
@@@ -202,64 -171,4 +202,64 @@@ int avfilter_graph_parse2(AVFilterGrap
                            AVFilterInOut **inputs,
                            AVFilterInOut **outputs);
  
-  * @return  the return value of avfilter_request_frame,
 +
 +/**
 + * Send a command to one or more filter instances.
 + *
 + * @param graph  the filter graph
 + * @param target the filter(s) to which the command should be sent
 + *               "all" sends to all filters
 + *               otherwise it can be a filter or filter instance name
 + *               which will send the command to all matching filters.
 + * @param cmd    the command to sent, for handling simplicity all commands must be alphanumeric only
 + * @param arg    the argument for the command
 + * @param res    a buffer with size res_size where the filter(s) can return a response.
 + *
 + * @returns >=0 on success otherwise an error code.
 + *              AVERROR(ENOSYS) on unsupported commands
 + */
 +int avfilter_graph_send_command(AVFilterGraph *graph, const char *target, const char *cmd, const char *arg, char *res, int res_len, int flags);
 +
 +/**
 + * Queue a command for one or more filter instances.
 + *
 + * @param graph  the filter graph
 + * @param target the filter(s) to which the command should be sent
 + *               "all" sends to all filters
 + *               otherwise it can be a filter or filter instance name
 + *               which will send the command to all matching filters.
 + * @param cmd    the command to sent, for handling simplicity all commands must be alphanummeric only
 + * @param arg    the argument for the command
 + * @param ts     time at which the command should be sent to the filter
 + *
 + * @note As this executes commands after this function returns, no return code
 + *       from the filter is provided, also AVFILTER_CMD_FLAG_ONE is not supported.
 + */
 +int avfilter_graph_queue_command(AVFilterGraph *graph, const char *target, const char *cmd, const char *arg, int flags, double ts);
 +
 +
 +/**
 + * Dump a graph into a human-readable string representation.
 + *
 + * @param graph    the graph to dump
 + * @param options  formatting options; currently ignored
 + * @return  a string, or NULL in case of memory allocation failure;
 + *          the string must be freed using av_free
 + */
 +char *avfilter_graph_dump(AVFilterGraph *graph, const char *options);
 +
 +/**
 + * Request a frame on the oldest sink link.
 + *
 + * If the request returns AVERROR_EOF, try the next.
 + *
 + * Note that this function is not meant to be the sole scheduling mechanism
 + * of a filtergraph, only a convenience function to help drain a filtergraph
 + * in a balanced way under normal circumstances.
 + *
++ * @return  the return value of ff_request_frame,
 + *          or AVERROR_EOF of all links returned AVERROR_EOF.
 + */
 +int avfilter_graph_request_oldest(AVFilterGraph *graph);
 +
  #endif /* AVFILTER_AVFILTERGRAPH_H */
@@@ -57,41 -47,14 +47,14 @@@ static av_cold void uninit(AVFilterCont
          av_audio_fifo_free(sink->audio_fifo);
  }
  
- static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
- {
-     BufferSinkContext *sink = ctx->priv;
-     if (!(sink->fifo = av_fifo_alloc(FIFO_INIT_SIZE*sizeof(AVFilterBufferRef*)))) {
-         av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo\n");
-         return AVERROR(ENOMEM);
-     }
-     return 0;
- }
- static void write_buf(AVFilterContext *ctx, AVFilterBufferRef *buf)
+ static void start_frame(AVFilterLink *link, AVFilterBufferRef *buf)
  {
-     BufferSinkContext *sink = ctx->priv;
-     if (av_fifo_space(sink->fifo) < sizeof(AVFilterBufferRef *) &&
-         (av_fifo_realloc2(sink->fifo, av_fifo_size(sink->fifo) * 2) < 0)) {
-             av_log(ctx, AV_LOG_ERROR, "Error reallocating the FIFO.\n");
-             return;
-     }
+     BufferSinkContext *s = link->dst->priv;
  
-     av_fifo_generic_write(sink->fifo, &buf, sizeof(buf), NULL);
- }
- static void end_frame(AVFilterLink *link)
- {
-     write_buf(link->dst, link->cur_buf);
 -    av_assert0(!s->cur_buf);
++//     av_assert0(!s->cur_buf);
+     s->cur_buf    = buf;
      link->cur_buf = NULL;
- }
- static void filter_samples(AVFilterLink *link, AVFilterBufferRef *buf)
- {
-     write_buf(link->dst, buf);
- }
+ };
  
  int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf)
  {
@@@ -179,10 -138,9 +138,9 @@@ int av_buffersink_read_samples(AVFilter
  }
  
  AVFilter avfilter_vsink_buffer = {
 -    .name      = "buffersink",
 +    .name      = "buffersink_old",
      .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
      .priv_size = sizeof(BufferSinkContext),
-     .init      = init,
      .uninit    = uninit,
  
      .inputs    = (AVFilterPad[]) {{ .name          = "default",
  };
  
  AVFilter avfilter_asink_abuffer = {
 -    .name      = "abuffersink",
 +    .name      = "abuffersink_old",
      .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
      .priv_size = sizeof(BufferSinkContext),
-     .init      = init,
      .uninit    = uninit,
  
      .inputs    = (AVFilterPad[]) {{ .name           = "default",
index c18eacd,0000000..aa1231d
mode 100644,000000..100644
--- /dev/null
@@@ -1,78 -1,0 +1,57 @@@
- void avfilter_set_common_pixel_formats(AVFilterContext *ctx, AVFilterFormats *formats)
- {
-     set_common_formats(ctx, formats, AVMEDIA_TYPE_VIDEO,
-                        offsetof(AVFilterLink, in_formats),
-                        offsetof(AVFilterLink, out_formats));
- }
- void avfilter_set_common_sample_formats(AVFilterContext *ctx, AVFilterFormats *formats)
- {
-     set_common_formats(ctx, formats, AVMEDIA_TYPE_AUDIO,
-                        offsetof(AVFilterLink, in_formats),
-                        offsetof(AVFilterLink, out_formats));
- }
- void avfilter_set_common_channel_layouts(AVFilterContext *ctx, AVFilterFormats *formats)
- {
-     set_common_formats(ctx, formats, AVMEDIA_TYPE_AUDIO,
-                        offsetof(AVFilterLink, in_channel_layouts),
-                        offsetof(AVFilterLink, out_channel_layouts));
- }
 +/*
 + * Filter layer - default implementations
 + * Copyright (c) 2007 Bobby Bingham
 + *
 + * 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
 + */
 +
 +#include "libavutil/avassert.h"
 +#include "libavutil/audioconvert.h"
 +#include "libavutil/imgutils.h"
 +#include "libavutil/samplefmt.h"
 +
 +#include "avfilter.h"
 +#include "internal.h"
 +#include "formats.h"
 +
 +static void set_common_formats(AVFilterContext *ctx, AVFilterFormats *fmts,
 +                               enum AVMediaType type, int offin, int offout)
 +{
 +    int i;
 +    for (i = 0; i < ctx->input_count; i++)
 +        if (ctx->inputs[i] && ctx->inputs[i]->type == type)
 +            ff_formats_ref(fmts, (AVFilterFormats **)((uint8_t *)ctx->inputs[i]+offout));
 +
 +    for (i = 0; i < ctx->output_count; i++)
 +        if (ctx->outputs[i] && ctx->outputs[i]->type == type)
 +            ff_formats_ref(fmts, (AVFilterFormats **)((uint8_t *)ctx->outputs[i]+offin));
 +
 +    if (!fmts->refcount) {
 +        av_free(fmts->formats);
 +        av_free(fmts->refs);
 +        av_free(fmts);
 +    }
 +}
 +
 +#if FF_API_PACKING
 +void avfilter_set_common_packing_formats(AVFilterContext *ctx, AVFilterFormats *formats)
 +{
 +    set_common_formats(ctx, formats, AVMEDIA_TYPE_AUDIO,
 +                       offsetof(AVFilterLink, in_packing),
 +                       offsetof(AVFilterLink, out_packing));
 +}
 +#endif
Simple merge
Simple merge
Simple merge
index d9c5de8,0000000..ca9b17a
mode 100644,000000..100644
--- /dev/null
@@@ -1,385 -1,0 +1,385 @@@
- { 0, 0}, { 8, 0}, { 0, 8}, { 8, 8}, { 4, 4}, {12, 4}, { 4,12}, {12,12}, { 0, 4}, { 8, 4}, { 0,12}, { 8,12}, { 4, 0}, {12, 0}, { 4, 8}, {12, 8}, { 2, 2}, {10, 2}, { 2,10}, {10,10}, { 6, 6}, {14, 6}, { 6,14}, {14,14}, { 2, 6}, {10, 6}, { 2,14}, {10,14}, { 6, 2}, {14, 2}, { 6,10}, {14,10}, { 0, 2}, { 8, 2}, { 0,10}, { 8,10}, { 4, 6}, {12, 6}, { 4,14}, {12,14}, { 0, 6}, { 8, 6}, { 0,14}, { 8,14}, { 4, 2}, {12, 2}, { 4,10}, {12,10}, { 2, 0}, {10, 0}, { 2, 8}, {10, 8}, { 6, 4}, {14, 4}, { 6,12}, {14,12}, { 2, 4}, {10, 4}, { 2,12}, {10,12}, { 6, 0}, {14, 0}, { 6, 8}, {14, 8}, { 1, 1}, { 9, 1}, { 1, 9}, { 9, 9}, { 5, 5}, {13, 5}, { 5,13}, {13,13}, { 1, 5}, { 9, 5}, { 1,13}, { 9,13}, { 5, 1}, {13, 1}, { 5, 9}, {13, 9}, { 3, 3}, {11, 3}, { 3,11}, {11,11}, { 7, 7}, {15, 7}, { 7,15}, {15,15}, { 3, 7}, {11, 7}, { 3,15}, {11,15}, { 7, 3}, {15, 3}, { 7,11}, {15,11}, { 1, 3}, { 9, 3}, { 1,11}, { 9,11}, { 5, 7}, {13, 7}, { 5,15}, {13,15}, { 1, 7}, { 9, 7}, { 1,15}, { 9,15}, { 5, 3}, {13, 3}, { 5,11}, {13,11}, { 3, 1}, {11, 1}, { 3, 9}, {11, 9}, { 7, 5}, {15, 5}, { 7,13}, {15,13}, { 3, 5}, {11, 5}, { 3,13}, {11,13}, { 7, 1}, {15, 1}, { 7, 9}, {15, 9}, { 0, 1}, { 8, 1}, { 0, 9}, { 8, 9}, { 4, 5}, {12, 5}, { 4,13}, {12,13}, { 0, 5}, { 8, 5}, { 0,13}, { 8,13}, { 4, 1}, {12, 1}, { 4, 9}, {12, 9}, { 2, 3}, {10, 3}, { 2,11}, {10,11}, { 6, 7}, {14, 7}, { 6,15}, {14,15}, { 2, 7}, {10, 7}, { 2,15}, {10,15}, { 6, 3}, {14, 3}, { 6,11}, {14,11}, { 0, 3}, { 8, 3}, { 0,11}, { 8,11}, { 4, 7}, {12, 7}, { 4,15}, {12,15}, { 0, 7}, { 8, 7}, { 0,15}, { 8,15}, { 4, 3}, {12, 3}, { 4,11}, {12,11}, { 2, 1}, {10, 1}, { 2, 9}, {10, 9}, { 6, 5}, {14, 5}, { 6,13}, {14,13}, { 2, 5}, {10, 5}, { 2,13}, {10,13}, { 6, 1}, {14, 1}, { 6, 9}, {14, 9}, { 1, 0}, { 9, 0}, { 1, 8}, { 9, 8}, { 5, 4}, {13, 4}, { 5,12}, {13,12}, { 1, 4}, { 9, 4}, { 1,12}, { 9,12}, { 5, 0}, {13, 0}, { 5, 8}, {13, 8}, { 3, 2}, {11, 2}, { 3,10}, {11,10}, { 7, 6}, {15, 6}, { 7,14}, {15,14}, { 3, 6}, {11, 6}, { 3,14}, {11,14}, { 7, 2}, {15, 2}, { 7,10}, {15,10}, { 1, 2}, { 9, 2}, { 1,10}, { 9,10}, { 5, 6}, {13, 6}, { 5,14}, {13,14}, { 1, 6}, { 9, 6}, { 1,14}, { 9,14}, { 5, 2}, {13, 2}, { 5,10}, {13,10}, { 3, 0}, {11, 0}, { 3, 8}, {11, 8}, { 7, 4}, {15, 4}, { 7,12}, {15,12}, { 3, 4}, {11, 4}, { 3,12}, {11,12}, { 7, 0}, {15, 0}, { 7, 8}, {15, 8},
 +/*
 + * Copyright (C) 2005 Michael Niedermayer <michaelni@gmx.at>
 + *
 + * This file is part of MPlayer.
 + *
 + * MPlayer is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * MPlayer 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 General Public License along
 + * with MPlayer; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + */
 +
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <string.h>
 +#include <inttypes.h>
 +#include <math.h>
 +#include <assert.h>
 +
 +#include "config.h"
 +
 +#include "mp_msg.h"
 +#include "cpudetect.h"
 +
 +#include "libavcodec/avcodec.h"
 +
 +#include "img_format.h"
 +#include "mp_image.h"
 +#include "vf.h"
 +#include "vd_ffmpeg.h"
 +#include "libvo/fastmemcpy.h"
 +
 +#define XMIN(a,b) ((a) < (b) ? (a) : (b))
 +
 +#define BLOCK 16
 +
 +//===========================================================================//
 +static const uint8_t  __attribute__((aligned(8))) dither[8][8]={
 +{  0*4,  48*4,  12*4,  60*4,   3*4,  51*4,  15*4,  63*4, },
 +{ 32*4,  16*4,  44*4,  28*4,  35*4,  19*4,  47*4,  31*4, },
 +{  8*4,  56*4,   4*4,  52*4,  11*4,  59*4,   7*4,  55*4, },
 +{ 40*4,  24*4,  36*4,  20*4,  43*4,  27*4,  39*4,  23*4, },
 +{  2*4,  50*4,  14*4,  62*4,   1*4,  49*4,  13*4,  61*4, },
 +{ 34*4,  18*4,  46*4,  30*4,  33*4,  17*4,  45*4,  29*4, },
 +{ 10*4,  58*4,   6*4,  54*4,   9*4,  57*4,   5*4,  53*4, },
 +{ 42*4,  26*4,  38*4,  22*4,  41*4,  25*4,  37*4,  21*4, },
 +};
 +
 +static const uint8_t offset[511][2]= {
 +{ 0, 0},
 +{ 0, 0}, { 8, 8},
 +{ 0, 0}, { 4, 4}, {12, 8}, { 8,12},
 +{ 0, 0}, {10, 2}, { 4, 4}, {14, 6}, { 8, 8}, { 2,10}, {12,12}, { 6,14},
 +
 +{ 0, 0}, {10, 2}, { 4, 4}, {14, 6}, { 8, 8}, { 2,10}, {12,12}, { 6,14},
 +{ 5, 1}, {15, 3}, { 9, 5}, { 3, 7}, {13, 9}, { 7,11}, { 1,13}, {11,15},
 +
 +{ 0, 0}, { 8, 0}, { 0, 8}, { 8, 8}, { 5, 1}, {13, 1}, { 5, 9}, {13, 9},
 +{ 2, 2}, {10, 2}, { 2,10}, {10,10}, { 7, 3}, {15, 3}, { 7,11}, {15,11},
 +{ 4, 4}, {12, 4}, { 4,12}, {12,12}, { 1, 5}, { 9, 5}, { 1,13}, { 9,13},
 +{ 6, 6}, {14, 6}, { 6,14}, {14,14}, { 3, 7}, {11, 7}, { 3,15}, {11,15},
 +
 +{ 0, 0}, { 8, 0}, { 0, 8}, { 8, 8}, { 4, 0}, {12, 0}, { 4, 8}, {12, 8},
 +{ 1, 1}, { 9, 1}, { 1, 9}, { 9, 9}, { 5, 1}, {13, 1}, { 5, 9}, {13, 9},
 +{ 3, 2}, {11, 2}, { 3,10}, {11,10}, { 7, 2}, {15, 2}, { 7,10}, {15,10},
 +{ 2, 3}, {10, 3}, { 2,11}, {10,11}, { 6, 3}, {14, 3}, { 6,11}, {14,11},
 +{ 0, 4}, { 8, 4}, { 0,12}, { 8,12}, { 4, 4}, {12, 4}, { 4,12}, {12,12},
 +{ 1, 5}, { 9, 5}, { 1,13}, { 9,13}, { 5, 5}, {13, 5}, { 5,13}, {13,13},
 +{ 3, 6}, {11, 6}, { 3,14}, {11,14}, { 7, 6}, {15, 6}, { 7,14}, {15,14},
 +{ 2, 7}, {10, 7}, { 2,15}, {10,15}, { 6, 7}, {14, 7}, { 6,15}, {14,15},
 +
 +{ 0, 0}, { 8, 0}, { 0, 8}, { 8, 8}, { 0, 2}, { 8, 2}, { 0,10}, { 8,10},
 +{ 0, 4}, { 8, 4}, { 0,12}, { 8,12}, { 0, 6}, { 8, 6}, { 0,14}, { 8,14},
 +{ 1, 1}, { 9, 1}, { 1, 9}, { 9, 9}, { 1, 3}, { 9, 3}, { 1,11}, { 9,11},
 +{ 1, 5}, { 9, 5}, { 1,13}, { 9,13}, { 1, 7}, { 9, 7}, { 1,15}, { 9,15},
 +{ 2, 0}, {10, 0}, { 2, 8}, {10, 8}, { 2, 2}, {10, 2}, { 2,10}, {10,10},
 +{ 2, 4}, {10, 4}, { 2,12}, {10,12}, { 2, 6}, {10, 6}, { 2,14}, {10,14},
 +{ 3, 1}, {11, 1}, { 3, 9}, {11, 9}, { 3, 3}, {11, 3}, { 3,11}, {11,11},
 +{ 3, 5}, {11, 5}, { 3,13}, {11,13}, { 3, 7}, {11, 7}, { 3,15}, {11,15},
 +{ 4, 0}, {12, 0}, { 4, 8}, {12, 8}, { 4, 2}, {12, 2}, { 4,10}, {12,10},
 +{ 4, 4}, {12, 4}, { 4,12}, {12,12}, { 4, 6}, {12, 6}, { 4,14}, {12,14},
 +{ 5, 1}, {13, 1}, { 5, 9}, {13, 9}, { 5, 3}, {13, 3}, { 5,11}, {13,11},
 +{ 5, 5}, {13, 5}, { 5,13}, {13,13}, { 5, 7}, {13, 7}, { 5,15}, {13,15},
 +{ 6, 0}, {14, 0}, { 6, 8}, {14, 8}, { 6, 2}, {14, 2}, { 6,10}, {14,10},
 +{ 6, 4}, {14, 4}, { 6,12}, {14,12}, { 6, 6}, {14, 6}, { 6,14}, {14,14},
 +{ 7, 1}, {15, 1}, { 7, 9}, {15, 9}, { 7, 3}, {15, 3}, { 7,11}, {15,11},
 +{ 7, 5}, {15, 5}, { 7,13}, {15,13}, { 7, 7}, {15, 7}, { 7,15}, {15,15},
 +
++{ 0, 0}, { 8, 0}, { 0, 8}, { 8, 8}, { 4, 4}, {12, 4}, { 4,12}, {12,12}, { 0, 4}, { 8, 4}, { 0,12}, { 8,12}, { 4, 0}, {12, 0}, { 4, 8}, {12, 8}, { 2, 2}, {10, 2}, { 2,10}, {10,10}, { 6, 6}, {14, 6}, { 6,14}, {14,14}, { 2, 6}, {10, 6}, { 2,14}, {10,14}, { 6, 2}, {14, 2}, { 6,10}, {14,10}, { 0, 2}, { 8, 2}, { 0,10}, { 8,10}, { 4, 6}, {12, 6}, { 4,14}, {12,14}, { 0, 6}, { 8, 6}, { 0,14}, { 8,14}, { 4, 2}, {12, 2}, { 4,10}, {12,10}, { 2, 0}, {10, 0}, { 2, 8}, {10, 8}, { 6, 4}, {14, 4}, { 6,12}, {14,12}, { 2, 4}, {10, 4}, { 2,12}, {10,12}, { 6, 0}, {14, 0}, { 6, 8}, {14, 8}, { 1, 1}, { 9, 1}, { 1, 9}, { 9, 9}, { 5, 5}, {13, 5}, { 5,13}, {13,13}, { 1, 5}, { 9, 5}, { 1,13}, { 9,13}, { 5, 1}, {13, 1}, { 5, 9}, {13, 9}, { 3, 3}, {11, 3}, { 3,11}, {11,11}, { 7, 7}, {15, 7}, { 7,15}, {15,15}, { 3, 7}, {11, 7}, { 3,15}, {11,15}, { 7, 3}, {15, 3}, { 7,11}, {15,11}, { 1, 3}, { 9, 3}, { 1,11}, { 9,11}, { 5, 7}, {13, 7}, { 5,15}, {13,15}, { 1, 7}, { 9, 7}, { 1,15}, { 9,15}, { 5, 3}, {13, 3}, { 5,11}, {13,11}, { 3, 1}, {11,1}, { 3, 9}, {11, 9}, { 7, 5}, {15, 5}, { 7,13}, {15,13}, { 3, 5}, {11, 5}, { 3,13}, {11,13}, { 7, 1}, {15, 1}, { 7, 9}, {15, 9}, { 0, 1}, { 8, 1}, { 0, 9}, { 8, 9}, { 4, 5}, {12, 5}, { 4,13}, {12,13}, { 0, 5}, { 8, 5}, { 0,13}, { 8,13}, { 4, 1}, {12, 1}, { 4, 9}, {12, 9}, { 2, 3}, {10, 3}, { 2,11}, {10,11}, { 6, 7}, {14, 7}, { 6,15}, {14,15}, { 2, 7}, {10, 7}, { 2,15}, {10,15}, { 6, 3}, {14, 3}, { 6,11}, {14,11}, { 0, 3}, { 8, 3}, { 0,11}, { 8,11}, { 4, 7}, {12, 7}, { 4,15}, {12,15}, { 0, 7}, { 8, 7}, { 0,15}, { 8,15}, { 4, 3}, {12, 3}, { 4,11}, {12,11}, { 2, 1}, {10, 1}, { 2, 9}, {10, 9}, { 6, 5}, {14, 5}, { 6,13}, {14,13}, { 2, 5}, {10, 5}, { 2,13}, {10,13}, { 6, 1}, {14, 1}, { 6, 9}, {14, 9}, { 1, 0}, { 9, 0}, { 1, 8}, { 9, 8}, { 5, 4}, {13, 4}, { 5,12}, {13,12}, { 1, 4}, { 9, 4}, { 1,12}, { 9,12}, { 5, 0}, {13, 0}, { 5, 8}, {13, 8}, { 3, 2}, {11, 2}, { 3,10}, {11,10}, { 7, 6}, {15, 6}, { 7,14}, {15,14}, { 3, 6}, {11, 6}, { 3,14}, {11,14}, { 7, 2}, {15, 2}, { 7,10}, {15,10}, { 1, 2}, { 9, 2}, { 1,10}, {9,10}, { 5, 6}, {13, 6}, { 5,14}, {13,14}, { 1, 6}, { 9, 6}, { 1,14}, { 9,14}, { 5, 2}, {13, 2}, { 5,10}, {13,10}, { 3, 0}, {11, 0}, { 3, 8}, {11, 8}, { 7, 4}, {15, 4}, { 7,12}, {15,12}, { 3, 4}, {11, 4}, { 3,12}, {11,12}, { 7, 0}, {15, 0}, { 7, 8}, {15, 8},
 +};
 +
 +struct vf_priv_s {
 +    int log2_count;
 +    int qp;
 +    int mode;
 +    int mpeg2;
 +    int temp_stride[3];
 +    uint8_t *src[3];
 +    int16_t *temp[3];
 +    int outbuf_size;
 +    uint8_t *outbuf;
 +    AVCodecContext *avctx_enc[BLOCK*BLOCK];
 +    AVFrame *frame;
 +    AVFrame *frame_dec;
 +};
 +
 +static void store_slice_c(uint8_t *dst, int16_t *src, int dst_stride, int src_stride, int width, int height, int log2_scale){
 +        int y, x;
 +
 +#define STORE(pos) \
 +        temp= ((src[x + y*src_stride + pos]<<log2_scale) + d[pos])>>8;\
 +        if(temp & 0x100) temp= ~(temp>>31);\
 +        dst[x + y*dst_stride + pos]= temp;
 +
 +        for(y=0; y<height; y++){
 +                const uint8_t *d= dither[y&7];
 +                for(x=0; x<width; x+=8){
 +                        int temp;
 +                        STORE(0);
 +                        STORE(1);
 +                        STORE(2);
 +                        STORE(3);
 +                        STORE(4);
 +                        STORE(5);
 +                        STORE(6);
 +                        STORE(7);
 +                }
 +        }
 +}
 +
 +static void filter(struct vf_priv_s *p, uint8_t *dst[3], uint8_t *src[3], int dst_stride[3], int src_stride[3], int width, int height, uint8_t *qp_store, int qp_stride){
 +    int x, y, i, j;
 +    const int count= 1<<p->log2_count;
 +
 +    for(i=0; i<3; i++){
 +        int is_chroma= !!i;
 +        int w= width >>is_chroma;
 +        int h= height>>is_chroma;
 +        int stride= p->temp_stride[i];
 +        int block= BLOCK>>is_chroma;
 +
 +        if (!src[i] || !dst[i])
 +            continue; // HACK avoid crash for Y8 colourspace
 +        for(y=0; y<h; y++){
 +            int index= block + block*stride + y*stride;
 +            fast_memcpy(p->src[i] + index, src[i] + y*src_stride[i], w);
 +            for(x=0; x<block; x++){
 +                p->src[i][index     - x - 1]= p->src[i][index +     x    ];
 +                p->src[i][index + w + x    ]= p->src[i][index + w - x - 1];
 +            }
 +        }
 +        for(y=0; y<block; y++){
 +            fast_memcpy(p->src[i] + (  block-1-y)*stride, p->src[i] + (  y+block  )*stride, stride);
 +            fast_memcpy(p->src[i] + (h+block  +y)*stride, p->src[i] + (h-y+block-1)*stride, stride);
 +        }
 +
 +        p->frame->linesize[i]= stride;
 +        memset(p->temp[i], 0, (h+2*block)*stride*sizeof(int16_t));
 +    }
 +
 +    if(p->qp)
 +        p->frame->quality= p->qp * FF_QP2LAMBDA;
 +    else
 +        p->frame->quality= norm_qscale(qp_store[0], p->mpeg2) * FF_QP2LAMBDA;
 +//    init per MB qscale stuff FIXME
 +
 +    for(i=0; i<count; i++){
 +        const int x1= offset[i+count-1][0];
 +        const int y1= offset[i+count-1][1];
 +        int offset;
 +        p->frame->data[0]= p->src[0] + x1 + y1 * p->frame->linesize[0];
 +        p->frame->data[1]= p->src[1] + x1/2 + y1/2 * p->frame->linesize[1];
 +        p->frame->data[2]= p->src[2] + x1/2 + y1/2 * p->frame->linesize[2];
 +
 +        avcodec_encode_video(p->avctx_enc[i], p->outbuf, p->outbuf_size, p->frame);
 +        p->frame_dec = p->avctx_enc[i]->coded_frame;
 +
 +        offset= (BLOCK-x1) + (BLOCK-y1)*p->frame_dec->linesize[0];
 +        //FIXME optimize
 +        for(y=0; y<height; y++){
 +            for(x=0; x<width; x++){
 +                p->temp[0][ x + y*p->temp_stride[0] ] += p->frame_dec->data[0][ x + y*p->frame_dec->linesize[0] + offset ];
 +            }
 +        }
 +        offset= (BLOCK/2-x1/2) + (BLOCK/2-y1/2)*p->frame_dec->linesize[1];
 +        for(y=0; y<height/2; y++){
 +            for(x=0; x<width/2; x++){
 +                p->temp[1][ x + y*p->temp_stride[1] ] += p->frame_dec->data[1][ x + y*p->frame_dec->linesize[1] + offset ];
 +                p->temp[2][ x + y*p->temp_stride[2] ] += p->frame_dec->data[2][ x + y*p->frame_dec->linesize[2] + offset ];
 +            }
 +        }
 +    }
 +
 +    for(j=0; j<3; j++){
 +        int is_chroma= !!j;
 +        store_slice_c(dst[j], p->temp[j], dst_stride[j], p->temp_stride[j], width>>is_chroma, height>>is_chroma, 8-p->log2_count);
 +    }
 +}
 +
 +static int config(struct vf_instance *vf,
 +        int width, int height, int d_width, int d_height,
 +        unsigned int flags, unsigned int outfmt){
 +        int i;
 +        AVCodec *enc= avcodec_find_encoder(CODEC_ID_SNOW);
 +
 +        for(i=0; i<3; i++){
 +            int is_chroma= !!i;
 +            int w= ((width  + 4*BLOCK-1) & (~(2*BLOCK-1)))>>is_chroma;
 +            int h= ((height + 4*BLOCK-1) & (~(2*BLOCK-1)))>>is_chroma;
 +
 +            vf->priv->temp_stride[i]= w;
 +            vf->priv->temp[i]= malloc(vf->priv->temp_stride[i]*h*sizeof(int16_t));
 +            vf->priv->src [i]= malloc(vf->priv->temp_stride[i]*h*sizeof(uint8_t));
 +        }
 +        for(i=0; i< (1<<vf->priv->log2_count); i++){
 +            AVCodecContext *avctx_enc;
 +
 +            avctx_enc=
 +            vf->priv->avctx_enc[i]= avcodec_alloc_context();
 +            avctx_enc->width = width + BLOCK;
 +            avctx_enc->height = height + BLOCK;
 +            avctx_enc->time_base= (AVRational){1,25};  // meaningless
 +            avctx_enc->gop_size = 300;
 +            avctx_enc->max_b_frames= 0;
 +            avctx_enc->pix_fmt = PIX_FMT_YUV420P;
 +            avctx_enc->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY;
 +            avctx_enc->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
 +            avctx_enc->global_quality= 123;
 +            avcodec_open(avctx_enc, enc);
 +            assert(avctx_enc->codec);
 +        }
 +        vf->priv->frame= avcodec_alloc_frame();
 +        vf->priv->frame_dec= avcodec_alloc_frame();
 +
 +        vf->priv->outbuf_size= (width + BLOCK)*(height + BLOCK)*10;
 +        vf->priv->outbuf= malloc(vf->priv->outbuf_size);
 +
 +        return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
 +}
 +
 +static void get_image(struct vf_instance *vf, mp_image_t *mpi){
 +    if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change
 +    // ok, we can do pp in-place (or pp disabled):
 +    vf->dmpi=vf_get_image(vf->next,mpi->imgfmt,
 +        mpi->type, mpi->flags | MP_IMGFLAG_READABLE, mpi->width, mpi->height);
 +    mpi->planes[0]=vf->dmpi->planes[0];
 +    mpi->stride[0]=vf->dmpi->stride[0];
 +    mpi->width=vf->dmpi->width;
 +    if(mpi->flags&MP_IMGFLAG_PLANAR){
 +        mpi->planes[1]=vf->dmpi->planes[1];
 +        mpi->planes[2]=vf->dmpi->planes[2];
 +        mpi->stride[1]=vf->dmpi->stride[1];
 +        mpi->stride[2]=vf->dmpi->stride[2];
 +    }
 +    mpi->flags|=MP_IMGFLAG_DIRECT;
 +}
 +
 +static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){
 +    mp_image_t *dmpi;
 +
 +    if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
 +        // no DR, so get a new image! hope we'll get DR buffer:
 +        dmpi=vf_get_image(vf->next,mpi->imgfmt,
 +            MP_IMGTYPE_TEMP,
 +            MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE,
 +            mpi->width,mpi->height);
 +        vf_clone_mpi_attributes(dmpi, mpi);
 +    }else{
 +        dmpi=vf->dmpi;
 +    }
 +
 +    vf->priv->mpeg2= mpi->qscale_type;
 +    if(vf->priv->log2_count || !(mpi->flags&MP_IMGFLAG_DIRECT)){
 +        if(mpi->qscale || vf->priv->qp){
 +            filter(vf->priv, dmpi->planes, mpi->planes, dmpi->stride, mpi->stride, mpi->w, mpi->h, mpi->qscale, mpi->qstride);
 +        }else{
 +            memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, dmpi->stride[0], mpi->stride[0]);
 +            memcpy_pic(dmpi->planes[1], mpi->planes[1], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, dmpi->stride[1], mpi->stride[1]);
 +            memcpy_pic(dmpi->planes[2], mpi->planes[2], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, dmpi->stride[2], mpi->stride[2]);
 +        }
 +    }
 +
 +#if HAVE_MMX
 +    if(gCpuCaps.hasMMX) __asm__ volatile ("emms\n\t");
 +#endif
 +#if HAVE_MMX2
 +    if(gCpuCaps.hasMMX2) __asm__ volatile ("sfence\n\t");
 +#endif
 +
 +    return vf_next_put_image(vf,dmpi, pts);
 +}
 +
 +static void uninit(struct vf_instance *vf){
 +    int i;
 +    if(!vf->priv) return;
 +
 +    for(i=0; i<3; i++){
 +        free(vf->priv->temp[i]);
 +        vf->priv->temp[i]= NULL;
 +        free(vf->priv->src[i]);
 +        vf->priv->src[i]= NULL;
 +    }
 +    for(i=0; i<BLOCK*BLOCK; i++){
 +        av_freep(&vf->priv->avctx_enc[i]);
 +    }
 +
 +    free(vf->priv);
 +    vf->priv=NULL;
 +}
 +
 +//===========================================================================//
 +static int query_format(struct vf_instance *vf, unsigned int fmt){
 +    switch(fmt){
 +        case IMGFMT_YV12:
 +        case IMGFMT_I420:
 +        case IMGFMT_IYUV:
 +        case IMGFMT_Y800:
 +        case IMGFMT_Y8:
 +            return vf_next_query_format(vf,fmt);
 +    }
 +    return 0;
 +}
 +
 +static int control(struct vf_instance *vf, int request, void* data){
 +    switch(request){
 +    case VFCTRL_QUERY_MAX_PP_LEVEL:
 +        return 8;
 +    case VFCTRL_SET_PP_LEVEL:
 +        vf->priv->log2_count= *((unsigned int*)data);
 +        //FIXME we have to realloc a few things here
 +        return CONTROL_TRUE;
 +    }
 +    return vf_next_control(vf,request,data);
 +}
 +
 +static int vf_open(vf_instance_t *vf, char *args){
 +
 +    int log2c=-1;
 +
 +    vf->config=config;
 +    vf->put_image=put_image;
 +    vf->get_image=get_image;
 +    vf->query_format=query_format;
 +    vf->uninit=uninit;
 +    vf->control= control;
 +    vf->priv=malloc(sizeof(struct vf_priv_s));
 +    memset(vf->priv, 0, sizeof(struct vf_priv_s));
 +
 +    init_avcodec();
 +
 +    vf->priv->log2_count= 4;
 +
 +    if (args) sscanf(args, "%d:%d:%d", &log2c, &vf->priv->qp, &vf->priv->mode);
 +
 +    if( log2c >=0 && log2c <=8 )
 +        vf->priv->log2_count = log2c;
 +
 +    if(vf->priv->qp < 0)
 +        vf->priv->qp = 0;
 +
 +// #if HAVE_MMX
 +//     if(gCpuCaps.hasMMX){
 +//         store_slice= store_slice_mmx;
 +//     }
 +// #endif
 +
 +    return 1;
 +}
 +
 +const vf_info_t vf_info_uspp = {
 +    "ultra simple/slow postprocess",
 +    "uspp",
 +    "Michael Niedermayer",
 +    "",
 +    vf_open,
 +    NULL
 +};
index 27f21b0,0000000..ad51639
mode 100644,000000..100644
--- /dev/null
@@@ -1,303 -1,0 +1,303 @@@
-         if ((ret = avfilter_request_frame(inlink)) < 0)
 +/*
 + * 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 video 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
 +
 +    /* 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);
 +    }
 +    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);
 +}
 +
 +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;
 +
 +    /* 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)
 +{
 +    return ctx->inputs[0]->frame_rate;
 +}
 +
 +int av_buffersink_poll_frame(AVFilterContext *ctx)
 +{
 +    BufferSinkContext *buf = ctx->priv;
 +    AVFilterLink *inlink = ctx->inputs[0];
 +
 +    return av_fifo_size(buf->fifo)/sizeof(AVFilterBufferRef *) + ff_poll_frame(inlink);
 +}
 +
 +#if FF_API_OLD_VSINK_API
 +int av_vsink_buffer_get_video_buffer_ref(AVFilterContext *ctx,
 +                                         AVFilterBufferRef **picref, int flags)
 +{
 +    return av_buffersink_get_buffer_ref(ctx, picref, flags);
 +}
 +#endif
 +
 +#if CONFIG_BUFFERSINK_FILTER
 +
 +static av_cold int vsink_init(AVFilterContext *ctx, const char *args, void *opaque)
 +{
 +    BufferSinkContext *buf = ctx->priv;
 +    av_unused AVBufferSinkParams *params;
 +
 +    if (!opaque) {
 +        av_log(ctx, AV_LOG_WARNING,
 +               "No opaque field provided\n");
 +        buf->pixel_fmts = NULL;
 +    } else {
 +#if FF_API_OLD_VSINK_API
 +        const int *pixel_fmts = (const enum PixelFormat *)opaque;
 +#else
 +        params = (AVBufferSinkParams *)opaque;
 +        const int *pixel_fmts = params->pixel_fmts;
 +#endif
 +        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 void filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
 +{
 +    end_frame(link);
 +}
 +
 +static av_cold int asink_init(AVFilterContext *ctx, const char *args, void *opaque)
 +{
 +    BufferSinkContext *buf = ctx->priv;
 +    AVABufferSinkParams *params;
 +
 +    if (!opaque) {
 +        av_log(ctx, AV_LOG_ERROR,
 +               "No opaque field provided, an AVABufferSinkParams struct is required\n");
 +        return AVERROR(EINVAL);
 +    } else
 +        params = (AVABufferSinkParams *)opaque;
 +
 +    buf->sample_fmts     = ff_copy_int_list  (params->sample_fmts);
 +    buf->channel_layouts = ff_copy_int64_list(params->channel_layouts);
 +    if (!buf->sample_fmts || !buf->channel_layouts) {
 +        av_freep(&buf->sample_fmts);
 +        av_freep(&buf->channel_layouts);
 +        return AVERROR(ENOMEM);
 +    }
 +
 +    return common_init(ctx);
 +}
 +
 +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 (!(formats = ff_make_format_list(buf->sample_fmts)))
 +        return AVERROR(ENOMEM);
 +    ff_set_common_formats(ctx, formats);
 +
 +    if (!(layouts = avfilter_make_format64_list(buf->channel_layouts)))
 +        return AVERROR(ENOMEM);
 +    ff_set_common_channel_layouts(ctx, layouts);
 +    ff_set_common_samplerates          (ctx, ff_all_samplerates());
 +
 +    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 */
@@@ -28,9 -28,9 +28,9 @@@
  
  #include "libavutil/avutil.h"
  
- #define LIBAVFILTER_VERSION_MAJOR  2
- #define LIBAVFILTER_VERSION_MINOR 82
+ #define LIBAVFILTER_VERSION_MAJOR  3
+ #define LIBAVFILTER_VERSION_MINOR  0
 -#define LIBAVFILTER_VERSION_MICRO  0
 +#define LIBAVFILTER_VERSION_MICRO 100
  
  #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
                                                 LIBAVFILTER_VERSION_MINOR, \
index 28020a4,0000000..9d29c45
mode 100644,000000..100644
--- /dev/null
@@@ -1,225 -1,0 +1,225 @@@
-     int ret = avfilter_request_frame(inlink);
 +/*
 + * 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
 + * Video black detector, loosely based on blackframe with extended
 + * syntax and features
 + */
 +
 +#include <float.h>
 +#include "libavutil/opt.h"
 +#include "libavutil/timestamp.h"
 +#include "avfilter.h"
 +#include "internal.h"
 +
 +typedef struct {
 +    const AVClass *class;
 +    double  black_min_duration_time; ///< minimum duration of detected black, in seconds
 +    int64_t black_min_duration;      ///< minimum duration of detected black, expressed in timebase units
 +    int64_t black_start;             ///< pts start time of the first black picture
 +    int64_t black_end;               ///< pts end time of the last black picture
 +    int64_t last_picref_pts;         ///< pts of the last input picture
 +    int black_started;
 +
 +    double       picture_black_ratio_th;
 +    double       pixel_black_th;
 +    unsigned int pixel_black_th_i;
 +
 +    unsigned int frame_count;       ///< frame number
 +    unsigned int nb_black_pixels;   ///< number of black pixels counted so far
 +} BlackDetectContext;
 +
 +#define OFFSET(x) offsetof(BlackDetectContext, x)
 +static const AVOption blackdetect_options[] = {
 +    { "d",                  "set minimum detected black duration in seconds", OFFSET(black_min_duration_time), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 0, DBL_MAX},
 +    { "black_min_duration", "set minimum detected black duration in seconds", OFFSET(black_min_duration_time), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 0, DBL_MAX},
 +    { "picture_black_ratio_th", "set the picture black ratio threshold", OFFSET(picture_black_ratio_th), AV_OPT_TYPE_DOUBLE, {.dbl=.98}, 0, 1},
 +    { "pic_th",                 "set the picture black ratio threshold", OFFSET(picture_black_ratio_th), AV_OPT_TYPE_DOUBLE, {.dbl=.98}, 0, 1},
 +    { "pixel_black_th", "set the pixel black threshold", OFFSET(pixel_black_th), AV_OPT_TYPE_DOUBLE, {.dbl=.10}, 0, 1},
 +    { "pix_th",         "set the pixel black threshold", OFFSET(pixel_black_th), AV_OPT_TYPE_DOUBLE, {.dbl=.10}, 0, 1},
 +    { NULL },
 +};
 +
 +AVFILTER_DEFINE_CLASS(blackdetect);
 +
 +#define YUVJ_FORMATS \
 +    PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ444P, PIX_FMT_YUVJ440P
 +
 +static enum PixelFormat yuvj_formats[] = {
 +    YUVJ_FORMATS, PIX_FMT_NONE
 +};
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    static const enum PixelFormat pix_fmts[] = {
 +        PIX_FMT_YUV410P, PIX_FMT_YUV420P, PIX_FMT_GRAY8, PIX_FMT_NV12,
 +        PIX_FMT_NV21, PIX_FMT_YUV444P, PIX_FMT_YUV422P, PIX_FMT_YUV411P,
 +        YUVJ_FORMATS,
 +        PIX_FMT_NONE
 +    };
 +
 +    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
 +    return 0;
 +}
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
 +{
 +    int ret;
 +    BlackDetectContext *blackdetect = ctx->priv;
 +
 +    blackdetect->class = &blackdetect_class;
 +    av_opt_set_defaults(blackdetect);
 +
 +    if ((ret = av_set_options_string(blackdetect, args, "=", ":")) < 0) {
 +        av_log(ctx, AV_LOG_ERROR, "Error parsing options string: '%s'\n", args);
 +        return ret;
 +    }
 +
 +    return 0;
 +}
 +
 +static int config_input(AVFilterLink *inlink)
 +{
 +    AVFilterContext *ctx = inlink->dst;
 +    BlackDetectContext *blackdetect = ctx->priv;
 +
 +    blackdetect->black_min_duration =
 +        blackdetect->black_min_duration_time / av_q2d(inlink->time_base);
 +
 +    blackdetect->pixel_black_th_i = ff_fmt_is_in(inlink->format, yuvj_formats) ?
 +        // luminance_minimum_value + pixel_black_th * luminance_range_size
 +             blackdetect->pixel_black_th *  255 :
 +        16 + blackdetect->pixel_black_th * (235 - 16);
 +
 +    av_log(blackdetect, AV_LOG_INFO,
 +           "black_min_duration:%s pixel_black_th:%f pixel_black_th_i:%d picture_black_ratio_th:%f\n",
 +           av_ts2timestr(blackdetect->black_min_duration, &inlink->time_base),
 +           blackdetect->pixel_black_th, blackdetect->pixel_black_th_i,
 +           blackdetect->picture_black_ratio_th);
 +    return 0;
 +}
 +
 +static void check_black_end(AVFilterContext *ctx)
 +{
 +    BlackDetectContext *blackdetect = ctx->priv;
 +    AVFilterLink *inlink = ctx->inputs[0];
 +
 +    if ((blackdetect->black_end - blackdetect->black_start) >= blackdetect->black_min_duration) {
 +        av_log(blackdetect, AV_LOG_INFO,
 +               "black_start:%s black_end:%s black_duration:%s\n",
 +               av_ts2timestr(blackdetect->black_start, &inlink->time_base),
 +               av_ts2timestr(blackdetect->black_end,   &inlink->time_base),
 +               av_ts2timestr(blackdetect->black_end - blackdetect->black_start, &inlink->time_base));
 +    }
 +}
 +
 +static int request_frame(AVFilterLink *outlink)
 +{
 +    AVFilterContext *ctx = outlink->src;
 +    BlackDetectContext *blackdetect = ctx->priv;
 +    AVFilterLink *inlink = ctx->inputs[0];
++    int ret = ff_request_frame(inlink);
 +
 +    if (ret == AVERROR_EOF && blackdetect->black_started) {
 +        // FIXME: black_end should be set to last_picref_pts + last_picref_duration
 +        blackdetect->black_end = blackdetect->last_picref_pts;
 +        check_black_end(ctx);
 +    }
 +    return ret;
 +}
 +
 +static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
 +{
 +    AVFilterContext *ctx = inlink->dst;
 +    BlackDetectContext *blackdetect = ctx->priv;
 +    AVFilterBufferRef *picref = inlink->cur_buf;
 +    int x, i;
 +    const uint8_t *p = picref->data[0] + y * picref->linesize[0];
 +
 +    for (i = 0; i < h; i++) {
 +        for (x = 0; x < inlink->w; x++)
 +            blackdetect->nb_black_pixels += p[x] <= blackdetect->pixel_black_th_i;
 +        p += picref->linesize[0];
 +    }
 +
 +    ff_draw_slice(ctx->outputs[0], y, h, slice_dir);
 +}
 +
 +static void end_frame(AVFilterLink *inlink)
 +{
 +    AVFilterContext *ctx = inlink->dst;
 +    BlackDetectContext *blackdetect = ctx->priv;
 +    AVFilterBufferRef *picref = inlink->cur_buf;
 +    double picture_black_ratio = 0;
 +
 +    picture_black_ratio = (double)blackdetect->nb_black_pixels / (inlink->w * inlink->h);
 +
 +    av_log(ctx, AV_LOG_DEBUG,
 +           "frame:%u picture_black_ratio:%f pos:%"PRId64" pts:%s t:%s type:%c\n",
 +           blackdetect->frame_count, picture_black_ratio,
 +           picref->pos, av_ts2str(picref->pts), av_ts2timestr(picref->pts, &inlink->time_base),
 +           av_get_picture_type_char(picref->video->pict_type));
 +
 +    if (picture_black_ratio >= blackdetect->picture_black_ratio_th) {
 +        if (!blackdetect->black_started) {
 +            /* black starts here */
 +            blackdetect->black_started = 1;
 +            blackdetect->black_start = picref->pts;
 +        }
 +    } else if (blackdetect->black_started) {
 +        /* black ends here */
 +        blackdetect->black_started = 0;
 +        blackdetect->black_end = picref->pts;
 +        check_black_end(ctx);
 +    }
 +
 +    blackdetect->last_picref_pts = picref->pts;
 +    blackdetect->frame_count++;
 +    blackdetect->nb_black_pixels = 0;
 +    avfilter_unref_buffer(picref);
 +    ff_end_frame(inlink->dst->outputs[0]);
 +}
 +
 +AVFilter avfilter_vf_blackdetect = {
 +    .name          = "blackdetect",
 +    .description   = NULL_IF_CONFIG_SMALL("Detect video intervals that are (almost) black."),
 +    .priv_size     = sizeof(BlackDetectContext),
 +    .init          = init,
 +    .query_formats = query_formats,
 +
 +    .inputs = (const AVFilterPad[]) {
 +        { .name             = "default",
 +          .type             = AVMEDIA_TYPE_VIDEO,
 +          .config_props     = config_input,
 +          .draw_slice       = draw_slice,
 +          .get_video_buffer = ff_null_get_video_buffer,
 +          .start_frame      = ff_null_start_frame_keep_ref,
 +          .end_frame        = end_frame, },
 +        { .name = NULL }
 +    },
 +
 +    .outputs = (const AVFilterPad[]) {
 +        { .name             = "default",
 +          .type             = AVMEDIA_TYPE_VIDEO,
 +          .request_frame    = request_frame, },
 +        { .name = NULL }
 +    },
 +};
index 48aad5f,0000000..1dcf7da
mode 100644,000000..100644
--- /dev/null
@@@ -1,338 -1,0 +1,338 @@@
-         if ((ret = avfilter_request_frame(link->src->inputs[0])))
 +/*
 + * Copyright (C) 2012 Michael Niedermayer <michaelni@gmx.at>
 + *
 + * 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
 + */
 +
 +#include "libavutil/cpu.h"
 +#include "libavutil/common.h"
 +#include "libavutil/pixdesc.h"
 +#include "avfilter.h"
 +#include "internal.h"
 +
 +#undef NDEBUG
 +#include <assert.h>
 +
 +#define HIST_SIZE 4
 +
 +typedef enum {
 +    TFF,
 +    BFF,
 +    PROGRSSIVE,
 +    UNDETERMINED,
 +} Type;
 +
 +typedef struct {
 +    float interlace_threshold;
 +    float progressive_threshold;
 +
 +    Type last_type;
 +    Type prestat[4];
 +    Type poststat[4];
 +
 +    uint8_t history[HIST_SIZE];
 +
 +    AVFilterBufferRef *cur;
 +    AVFilterBufferRef *next;
 +    AVFilterBufferRef *prev;
 +    AVFilterBufferRef *out;
 +    int (*filter_line)(const uint8_t *prev, const uint8_t *cur, const uint8_t *next, int w);
 +
 +    const AVPixFmtDescriptor *csp;
 +} IDETContext;
 +
 +static const char *type2str(Type type)
 +{
 +    switch(type) {
 +        case TFF         : return "Top Field First   ";
 +        case BFF         : return "Bottom Field First";
 +        case PROGRSSIVE  : return "Progressive       ";
 +        case UNDETERMINED: return "Undetermined      ";
 +    }
 +    return NULL;
 +}
 +
 +static int filter_line_c(const uint8_t *a, const uint8_t *b, const uint8_t *c, int w)
 +{
 +    int x;
 +    int ret=0;
 +
 +    for(x=0; x<w; x++){
 +        ret += FFABS((*a++ + *c++) - 2 * *b++);
 +    }
 +
 +    return ret;
 +}
 +
 +static int filter_line_c_16bit(const uint16_t *a, const uint16_t *b, const uint16_t *c, int w)
 +{
 +    int x;
 +    int ret=0;
 +
 +    for(x=0; x<w; x++){
 +        ret += FFABS((*a++ + *c++) - 2 * *b++);
 +    }
 +
 +    return ret;
 +}
 +
 +static void filter(AVFilterContext *ctx)
 +{
 +    IDETContext *idet = ctx->priv;
 +    int y, i;
 +    int64_t alpha[2]={0};
 +    int64_t delta=0;
 +    Type type, best_type;
 +    int match = 0;
 +
 +    for (i = 0; i < idet->csp->nb_components; i++) {
 +        int w = idet->cur->video->w;
 +        int h = idet->cur->video->h;
 +        int refs = idet->cur->linesize[i];
 +
 +        if (i && i<3) {
 +            w >>= idet->csp->log2_chroma_w;
 +            h >>= idet->csp->log2_chroma_h;
 +        }
 +
 +        for (y = 2; y < h - 2; y++) {
 +            uint8_t *prev = &idet->prev->data[i][y*refs];
 +            uint8_t *cur  = &idet->cur ->data[i][y*refs];
 +            uint8_t *next = &idet->next->data[i][y*refs];
 +            alpha[ y   &1] += idet->filter_line(cur-refs, prev, cur+refs, w);
 +            alpha[(y^1)&1] += idet->filter_line(cur-refs, next, cur+refs, w);
 +            delta          += idet->filter_line(cur-refs,  cur, cur+refs, w);
 +        }
 +    }
 +#if HAVE_MMX
 +    __asm__ volatile("emms \n\t" : : : "memory");
 +#endif
 +
 +    if      (alpha[0] / (float)alpha[1] > idet->interlace_threshold){
 +        type = TFF;
 +    }else if(alpha[1] / (float)alpha[0] > idet->interlace_threshold){
 +        type = BFF;
 +    }else if(alpha[1] / (float)delta    > idet->progressive_threshold){
 +        type = PROGRSSIVE;
 +    }else{
 +        type = UNDETERMINED;
 +    }
 +
 +    memmove(idet->history+1, idet->history, HIST_SIZE-1);
 +    idet->history[0] = type;
 +    best_type = UNDETERMINED;
 +    for(i=0; i<HIST_SIZE; i++){
 +        if(idet->history[i] != UNDETERMINED){
 +            if(best_type == UNDETERMINED)
 +                best_type = idet->history[i];
 +
 +            if(idet->history[i] == best_type) {
 +                match++;
 +            }else{
 +                match=0;
 +                break;
 +            }
 +        }
 +    }
 +    if(idet->last_type == UNDETERMINED){
 +        if(match  ) idet->last_type = best_type;
 +    }else{
 +        if(match>2) idet->last_type = best_type;
 +    }
 +
 +    if      (idet->last_type == TFF){
 +        idet->cur->video->top_field_first = 1;
 +        idet->cur->video->interlaced = 1;
 +    }else if(idet->last_type == BFF){
 +        idet->cur->video->top_field_first = 0;
 +        idet->cur->video->interlaced = 1;
 +    }else if(idet->last_type == PROGRSSIVE){
 +        idet->cur->video->interlaced = 0;
 +    }
 +
 +    idet->prestat [           type] ++;
 +    idet->poststat[idet->last_type] ++;
 +    av_log(ctx, AV_LOG_DEBUG, "Single frame:%s, Multi frame:%s\n", type2str(type), type2str(idet->last_type));
 +}
 +
 +static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
 +{
 +    AVFilterContext *ctx = link->dst;
 +    IDETContext *idet = ctx->priv;
 +
 +    if (idet->prev)
 +        avfilter_unref_buffer(idet->prev);
 +    idet->prev = idet->cur;
 +    idet->cur  = idet->next;
 +    idet->next = picref;
 +
 +    if (!idet->cur)
 +        return;
 +
 +    if (!idet->prev)
 +        idet->prev = avfilter_ref_buffer(idet->cur, AV_PERM_READ);
 +
 +    ff_start_frame(ctx->outputs[0], avfilter_ref_buffer(idet->cur, AV_PERM_READ));
 +}
 +
 +static void end_frame(AVFilterLink *link)
 +{
 +    AVFilterContext *ctx = link->dst;
 +    IDETContext *idet = ctx->priv;
 +
 +    if (!idet->cur)
 +        return;
 +
 +    if (!idet->csp)
 +        idet->csp = &av_pix_fmt_descriptors[link->format];
 +    if (idet->csp->comp[0].depth_minus1 / 8 == 1)
 +        idet->filter_line = (void*)filter_line_c_16bit;
 +
 +    filter(ctx);
 +
 +    ff_draw_slice(ctx->outputs[0], 0, link->h, 1);
 +    ff_end_frame(ctx->outputs[0]);
 +}
 +
 +static int request_frame(AVFilterLink *link)
 +{
 +    AVFilterContext *ctx = link->src;
 +    IDETContext *idet = ctx->priv;
 +
 +    do {
 +        int ret;
 +
-         if ((ret = avfilter_request_frame(link->src->inputs[0])) < 0)
++        if ((ret = ff_request_frame(link->src->inputs[0])))
 +            return ret;
 +    } while (!idet->cur);
 +
 +    return 0;
 +}
 +
 +static int poll_frame(AVFilterLink *link)
 +{
 +    IDETContext *idet = link->src->priv;
 +    int ret, val;
 +
 +    val = ff_poll_frame(link->src->inputs[0]);
 +
 +    if (val >= 1 && !idet->next) { //FIXME change API to not requre this red tape
++        if ((ret = ff_request_frame(link->src->inputs[0])) < 0)
 +            return ret;
 +        val = ff_poll_frame(link->src->inputs[0]);
 +    }
 +    assert(idet->next || !val);
 +
 +    return val;
 +}
 +
 +static av_cold void uninit(AVFilterContext *ctx)
 +{
 +    IDETContext *idet = ctx->priv;
 +
 +    av_log(ctx, AV_LOG_INFO, "Single frame detection: TFF:%d BFF:%d Progressive:%d Undetermined:%d\n",
 +           idet->prestat[TFF],
 +           idet->prestat[BFF],
 +           idet->prestat[PROGRSSIVE],
 +           idet->prestat[UNDETERMINED]
 +    );
 +    av_log(ctx, AV_LOG_INFO, "Multi frame detection: TFF:%d BFF:%d Progressive:%d Undetermined:%d\n",
 +           idet->poststat[TFF],
 +           idet->poststat[BFF],
 +           idet->poststat[PROGRSSIVE],
 +           idet->poststat[UNDETERMINED]
 +    );
 +
 +    if (idet->prev) avfilter_unref_buffer(idet->prev);
 +    if (idet->cur ) avfilter_unref_buffer(idet->cur );
 +    if (idet->next) avfilter_unref_buffer(idet->next);
 +}
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    static const enum PixelFormat pix_fmts[] = {
 +        PIX_FMT_YUV420P,
 +        PIX_FMT_YUV422P,
 +        PIX_FMT_YUV444P,
 +        PIX_FMT_YUV410P,
 +        PIX_FMT_YUV411P,
 +        PIX_FMT_GRAY8,
 +        PIX_FMT_YUVJ420P,
 +        PIX_FMT_YUVJ422P,
 +        PIX_FMT_YUVJ444P,
 +        AV_NE( PIX_FMT_GRAY16BE, PIX_FMT_GRAY16LE ),
 +        PIX_FMT_YUV440P,
 +        PIX_FMT_YUVJ440P,
 +        AV_NE( PIX_FMT_YUV420P10BE, PIX_FMT_YUV420P10LE ),
 +        AV_NE( PIX_FMT_YUV422P10BE, PIX_FMT_YUV422P10LE ),
 +        AV_NE( PIX_FMT_YUV444P10BE, PIX_FMT_YUV444P10LE ),
 +        AV_NE( PIX_FMT_YUV420P16BE, PIX_FMT_YUV420P16LE ),
 +        AV_NE( PIX_FMT_YUV422P16BE, PIX_FMT_YUV422P16LE ),
 +        AV_NE( PIX_FMT_YUV444P16BE, PIX_FMT_YUV444P16LE ),
 +        PIX_FMT_YUVA420P,
 +        PIX_FMT_NONE
 +    };
 +
 +    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
 +
 +    return 0;
 +}
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
 +{
 +    IDETContext *idet = ctx->priv;
 +
 +    idet->csp = NULL;
 +
 +    idet->interlace_threshold   = 1.01;
 +    idet->progressive_threshold = 2.5;
 +
 +    if (args) sscanf(args, "%f:%f", &idet->interlace_threshold, &idet->progressive_threshold);
 +
 +    idet->last_type = UNDETERMINED;
 +    memset(idet->history, UNDETERMINED, HIST_SIZE);
 +
 +    idet->filter_line = filter_line_c;
 +
 +    return 0;
 +}
 +
 +static void null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) { }
 +
 +AVFilter avfilter_vf_idet = {
 +    .name          = "idet",
 +    .description   = NULL_IF_CONFIG_SMALL("Interlace detect Filter."),
 +
 +    .priv_size     = sizeof(IDETContext),
 +    .init          = init,
 +    .uninit        = uninit,
 +    .query_formats = query_formats,
 +
 +    .inputs    = (const AVFilterPad[]) {{ .name       = "default",
 +                                          .type             = AVMEDIA_TYPE_VIDEO,
 +                                          .start_frame      = start_frame,
 +                                          .draw_slice       = null_draw_slice,
 +                                          .end_frame        = end_frame,
 +                                          .rej_perms        = AV_PERM_REUSE2, },
 +                                        { .name = NULL}},
 +
 +    .outputs   = (const AVFilterPad[]) {{ .name       = "default",
 +                                          .type             = AVMEDIA_TYPE_VIDEO,
 +                                          .poll_frame       = poll_frame,
 +                                          .request_frame    = request_frame, },
 +                                        { .name = NULL}},
 +};
index bf3975a,0000000..43eecc3
mode 100644,000000..100644
--- /dev/null
@@@ -1,908 -1,0 +1,911 @@@
-     avfilter_start_frame(outlink, avfilter_ref_buffer(picref, ~0));
-     avfilter_draw_slice(outlink, 0, picref->video->h, 1);
-     avfilter_end_frame(outlink);
 +/*
 + * Copyright (c) 2011 Michael Niedermayer
 + *
 + * This file is part of FFmpeg.
 + *
 + * FFmpeg is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 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 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
 + *
 + * Parts of this file have been stolen from mplayer
 + */
 +
 +/**
 + * @file
 + */
 +
 +#include "avfilter.h"
++#include "video.h"
++#include "formats.h"
++#include "internal.h"
 +#include "libavutil/avassert.h"
 +#include "libavutil/pixdesc.h"
 +#include "libavutil/intreadwrite.h"
 +#include "libavutil/imgutils.h"
 +
 +#include "libmpcodecs/vf.h"
 +#include "libmpcodecs/img_format.h"
 +#include "libmpcodecs/cpudetect.h"
 +#include "libmpcodecs/vd_ffmpeg.h"
 +#include "libmpcodecs/vf_scale.h"
 +#include "libmpcodecs/libvo/fastmemcpy.h"
 +
 +#include "libswscale/swscale.h"
 +
 +
 +//FIXME maybe link the orig in
 +//XXX: identical pix_fmt must be following with each others
 +static const struct {
 +    int fmt;
 +    enum PixelFormat pix_fmt;
 +} conversion_map[] = {
 +    {IMGFMT_ARGB, PIX_FMT_ARGB},
 +    {IMGFMT_BGRA, PIX_FMT_BGRA},
 +    {IMGFMT_BGR24, PIX_FMT_BGR24},
 +    {IMGFMT_BGR16BE, PIX_FMT_RGB565BE},
 +    {IMGFMT_BGR16LE, PIX_FMT_RGB565LE},
 +    {IMGFMT_BGR15BE, PIX_FMT_RGB555BE},
 +    {IMGFMT_BGR15LE, PIX_FMT_RGB555LE},
 +    {IMGFMT_BGR12BE, PIX_FMT_RGB444BE},
 +    {IMGFMT_BGR12LE, PIX_FMT_RGB444LE},
 +    {IMGFMT_BGR8,  PIX_FMT_RGB8},
 +    {IMGFMT_BGR4,  PIX_FMT_RGB4},
 +    {IMGFMT_BGR1,  PIX_FMT_MONOBLACK},
 +    {IMGFMT_RGB1,  PIX_FMT_MONOBLACK},
 +    {IMGFMT_RG4B,  PIX_FMT_BGR4_BYTE},
 +    {IMGFMT_BG4B,  PIX_FMT_RGB4_BYTE},
 +    {IMGFMT_RGB48LE, PIX_FMT_RGB48LE},
 +    {IMGFMT_RGB48BE, PIX_FMT_RGB48BE},
 +    {IMGFMT_ABGR, PIX_FMT_ABGR},
 +    {IMGFMT_RGBA, PIX_FMT_RGBA},
 +    {IMGFMT_RGB24, PIX_FMT_RGB24},
 +    {IMGFMT_RGB16BE, PIX_FMT_BGR565BE},
 +    {IMGFMT_RGB16LE, PIX_FMT_BGR565LE},
 +    {IMGFMT_RGB15BE, PIX_FMT_BGR555BE},
 +    {IMGFMT_RGB15LE, PIX_FMT_BGR555LE},
 +    {IMGFMT_RGB12BE, PIX_FMT_BGR444BE},
 +    {IMGFMT_RGB12LE, PIX_FMT_BGR444LE},
 +    {IMGFMT_RGB8,  PIX_FMT_BGR8},
 +    {IMGFMT_RGB4,  PIX_FMT_BGR4},
 +    {IMGFMT_BGR8,  PIX_FMT_PAL8},
 +    {IMGFMT_YUY2,  PIX_FMT_YUYV422},
 +    {IMGFMT_UYVY,  PIX_FMT_UYVY422},
 +    {IMGFMT_NV12,  PIX_FMT_NV12},
 +    {IMGFMT_NV21,  PIX_FMT_NV21},
 +    {IMGFMT_Y800,  PIX_FMT_GRAY8},
 +    {IMGFMT_Y8,    PIX_FMT_GRAY8},
 +    {IMGFMT_YVU9,  PIX_FMT_YUV410P},
 +    {IMGFMT_IF09,  PIX_FMT_YUV410P},
 +    {IMGFMT_YV12,  PIX_FMT_YUV420P},
 +    {IMGFMT_I420,  PIX_FMT_YUV420P},
 +    {IMGFMT_IYUV,  PIX_FMT_YUV420P},
 +    {IMGFMT_411P,  PIX_FMT_YUV411P},
 +    {IMGFMT_422P,  PIX_FMT_YUV422P},
 +    {IMGFMT_444P,  PIX_FMT_YUV444P},
 +    {IMGFMT_440P,  PIX_FMT_YUV440P},
 +
 +    {IMGFMT_420A,  PIX_FMT_YUVA420P},
 +
 +    {IMGFMT_420P16_LE,  PIX_FMT_YUV420P16LE},
 +    {IMGFMT_420P16_BE,  PIX_FMT_YUV420P16BE},
 +    {IMGFMT_422P16_LE,  PIX_FMT_YUV422P16LE},
 +    {IMGFMT_422P16_BE,  PIX_FMT_YUV422P16BE},
 +    {IMGFMT_444P16_LE,  PIX_FMT_YUV444P16LE},
 +    {IMGFMT_444P16_BE,  PIX_FMT_YUV444P16BE},
 +
 +    // YUVJ are YUV formats that use the full Y range and not just
 +    // 16 - 235 (see colorspaces.txt).
 +    // Currently they are all treated the same way.
 +    {IMGFMT_YV12,  PIX_FMT_YUVJ420P},
 +    {IMGFMT_422P,  PIX_FMT_YUVJ422P},
 +    {IMGFMT_444P,  PIX_FMT_YUVJ444P},
 +    {IMGFMT_440P,  PIX_FMT_YUVJ440P},
 +
 +    {IMGFMT_XVMC_MOCO_MPEG2, PIX_FMT_XVMC_MPEG2_MC},
 +    {IMGFMT_XVMC_IDCT_MPEG2, PIX_FMT_XVMC_MPEG2_IDCT},
 +    {IMGFMT_VDPAU_MPEG1,     PIX_FMT_VDPAU_MPEG1},
 +    {IMGFMT_VDPAU_MPEG2,     PIX_FMT_VDPAU_MPEG2},
 +    {IMGFMT_VDPAU_H264,      PIX_FMT_VDPAU_H264},
 +    {IMGFMT_VDPAU_WMV3,      PIX_FMT_VDPAU_WMV3},
 +    {IMGFMT_VDPAU_VC1,       PIX_FMT_VDPAU_VC1},
 +    {IMGFMT_VDPAU_MPEG4,     PIX_FMT_VDPAU_MPEG4},
 +    {0, PIX_FMT_NONE}
 +};
 +
 +//copied from vf.c
 +extern const vf_info_t vf_info_1bpp;
 +extern const vf_info_t vf_info_ass;
 +extern const vf_info_t vf_info_bmovl;
 +extern const vf_info_t vf_info_crop;
 +extern const vf_info_t vf_info_decimate;
 +extern const vf_info_t vf_info_denoise3d;
 +extern const vf_info_t vf_info_detc;
 +extern const vf_info_t vf_info_dint;
 +extern const vf_info_t vf_info_divtc;
 +extern const vf_info_t vf_info_down3dright;
 +extern const vf_info_t vf_info_dsize;
 +extern const vf_info_t vf_info_dvbscale;
 +extern const vf_info_t vf_info_eq2;
 +extern const vf_info_t vf_info_eq;
 +extern const vf_info_t vf_info_expand;
 +extern const vf_info_t vf_info_field;
 +extern const vf_info_t vf_info_fil;
 +extern const vf_info_t vf_info_filmdint;
 +extern const vf_info_t vf_info_fixpts;
 +extern const vf_info_t vf_info_flip;
 +extern const vf_info_t vf_info_format;
 +extern const vf_info_t vf_info_framestep;
 +extern const vf_info_t vf_info_fspp;
 +extern const vf_info_t vf_info_geq;
 +extern const vf_info_t vf_info_halfpack;
 +extern const vf_info_t vf_info_harddup;
 +extern const vf_info_t vf_info_hqdn3d;
 +extern const vf_info_t vf_info_hue;
 +extern const vf_info_t vf_info_il;
 +extern const vf_info_t vf_info_ilpack;
 +extern const vf_info_t vf_info_ivtc;
 +extern const vf_info_t vf_info_kerndeint;
 +extern const vf_info_t vf_info_lavc;
 +extern const vf_info_t vf_info_lavcdeint;
 +extern const vf_info_t vf_info_mcdeint;
 +extern const vf_info_t vf_info_noformat;
 +extern const vf_info_t vf_info_noise;
 +extern const vf_info_t vf_info_ow;
 +extern const vf_info_t vf_info_palette;
 +extern const vf_info_t vf_info_perspective;
 +extern const vf_info_t vf_info_phase;
 +extern const vf_info_t vf_info_pp7;
 +extern const vf_info_t vf_info_pp;
 +extern const vf_info_t vf_info_pullup;
 +extern const vf_info_t vf_info_qp;
 +extern const vf_info_t vf_info_rectangle;
 +extern const vf_info_t vf_info_rotate;
 +extern const vf_info_t vf_info_sab;
 +extern const vf_info_t vf_info_scale;
 +extern const vf_info_t vf_info_smartblur;
 +extern const vf_info_t vf_info_softpulldown;
 +extern const vf_info_t vf_info_softskip;
 +extern const vf_info_t vf_info_spp;
 +extern const vf_info_t vf_info_stereo3d;
 +extern const vf_info_t vf_info_telecine;
 +extern const vf_info_t vf_info_test;
 +extern const vf_info_t vf_info_tfields;
 +extern const vf_info_t vf_info_tile;
 +extern const vf_info_t vf_info_tinterlace;
 +extern const vf_info_t vf_info_unsharp;
 +extern const vf_info_t vf_info_uspp;
 +extern const vf_info_t vf_info_vo;
 +extern const vf_info_t vf_info_yadif;
 +extern const vf_info_t vf_info_yuvcsp;
 +extern const vf_info_t vf_info_yvu9;
 +extern const vf_info_t vf_info_zrmjpeg;
 +
 +
 +static const vf_info_t* const filters[]={
 +    &vf_info_decimate,
 +    &vf_info_denoise3d,
 +    &vf_info_detc,
 +    &vf_info_dint,
 +    &vf_info_divtc,
 +    &vf_info_down3dright,
 +    &vf_info_dsize,
 +    &vf_info_eq2,
 +    &vf_info_eq,
 +    &vf_info_field,
 +    &vf_info_fil,
 +//    &vf_info_filmdint, cmmx.h vd.h ‘opt_screen_size_x’
 +    &vf_info_fixpts,
 +    &vf_info_framestep,
 +    &vf_info_fspp,
 +    &vf_info_geq,
 +    &vf_info_harddup,
 +    &vf_info_hqdn3d,
 +    &vf_info_hue,
 +    &vf_info_il,
 +    &vf_info_ilpack,
 +    &vf_info_ivtc,
 +    &vf_info_kerndeint,
 +    &vf_info_mcdeint,
 +    &vf_info_noise,
 +    &vf_info_ow,
 +    &vf_info_palette,
 +    &vf_info_perspective,
 +    &vf_info_phase,
 +    &vf_info_pp,
 +    &vf_info_pp7,
 +    &vf_info_pullup,
 +    &vf_info_qp,
 +    &vf_info_rectangle,
 +    &vf_info_rotate,
 +    &vf_info_sab,
 +    &vf_info_smartblur,
 +    &vf_info_softpulldown,
 +    &vf_info_softskip,
 +    &vf_info_spp,
 +    &vf_info_stereo3d,
 +    &vf_info_telecine,
 +    &vf_info_tile,
 +    &vf_info_tinterlace,
 +    &vf_info_unsharp,
 +    &vf_info_uspp,
 +    &vf_info_yuvcsp,
 +    &vf_info_yvu9,
 +
 +    NULL
 +};
 +
 +/*
 +Unsupported filters
 +1bpp
 +ass
 +bmovl
 +crop
 +dvbscale
 +flip
 +expand
 +format
 +halfpack
 +lavc
 +lavcdeint
 +noformat
 +pp
 +scale
 +tfields
 +vo
 +yadif
 +zrmjpeg
 +*/
 +
 +CpuCaps gCpuCaps; //FIXME initialize this so optims work
 +
 +
 +static void sws_getFlagsAndFilterFromCmdLine(int *flags, SwsFilter **srcFilterParam, SwsFilter **dstFilterParam)
 +{
 +        static int firstTime=1;
 +        *flags=0;
 +
 +#if ARCH_X86
 +        if(gCpuCaps.hasMMX)
 +                __asm__ volatile("emms\n\t"::: "memory"); //FIXME this should not be required but it IS (even for non-MMX versions)
 +#endif
 +        if(firstTime)
 +        {
 +                firstTime=0;
 +                *flags= SWS_PRINT_INFO;
 +        }
 +        else if( mp_msg_test(MSGT_VFILTER,MSGL_DBG2) ) *flags= SWS_PRINT_INFO;
 +
 +        switch(SWS_BILINEAR)
 +        {
 +                case 0: *flags|= SWS_FAST_BILINEAR; break;
 +                case 1: *flags|= SWS_BILINEAR; break;
 +                case 2: *flags|= SWS_BICUBIC; break;
 +                case 3: *flags|= SWS_X; break;
 +                case 4: *flags|= SWS_POINT; break;
 +                case 5: *flags|= SWS_AREA; break;
 +                case 6: *flags|= SWS_BICUBLIN; break;
 +                case 7: *flags|= SWS_GAUSS; break;
 +                case 8: *flags|= SWS_SINC; break;
 +                case 9: *flags|= SWS_LANCZOS; break;
 +                case 10:*flags|= SWS_SPLINE; break;
 +                default:*flags|= SWS_BILINEAR; break;
 +        }
 +
 +        *srcFilterParam= NULL;
 +        *dstFilterParam= NULL;
 +}
 +
 +//exact copy from vf_scale.c
 +// will use sws_flags & src_filter (from cmd line)
 +struct SwsContext *sws_getContextFromCmdLine(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat)
 +{
 +        int flags, i;
 +        SwsFilter *dstFilterParam, *srcFilterParam;
 +        enum PixelFormat dfmt, sfmt;
 +
 +        for(i=0; conversion_map[i].fmt && dstFormat != conversion_map[i].fmt; i++);
 +        dfmt= conversion_map[i].pix_fmt;
 +        for(i=0; conversion_map[i].fmt && srcFormat != conversion_map[i].fmt; i++);
 +        sfmt= conversion_map[i].pix_fmt;
 +
 +        if (srcFormat == IMGFMT_RGB8 || srcFormat == IMGFMT_BGR8) sfmt = PIX_FMT_PAL8;
 +        sws_getFlagsAndFilterFromCmdLine(&flags, &srcFilterParam, &dstFilterParam);
 +
 +        return sws_getContext(srcW, srcH, sfmt, dstW, dstH, dfmt, flags , srcFilterParam, dstFilterParam, NULL);
 +}
 +
 +typedef struct {
 +    vf_instance_t vf;
 +    vf_instance_t next_vf;
 +    AVFilterContext *avfctx;
 +    int frame_returned;
 +} MPContext;
 +
 +void mp_msg(int mod, int lev, const char *format, ... ){
 +    va_list va;
 +    va_start(va, format);
 +    //FIXME convert lev/mod
 +    av_vlog(NULL, AV_LOG_DEBUG, format, va);
 +    va_end(va);
 +}
 +
 +int mp_msg_test(int mod, int lev){
 +    return 123;
 +}
 +
 +void init_avcodec(void)
 +{
 +    //we maybe should init but its kinda 1. unneeded 2. a bit inpolite from here
 +}
 +
 +//Exact copy of vf.c
 +void vf_clone_mpi_attributes(mp_image_t* dst, mp_image_t* src){
 +    dst->pict_type= src->pict_type;
 +    dst->fields = src->fields;
 +    dst->qscale_type= src->qscale_type;
 +    if(dst->width == src->width && dst->height == src->height){
 +        dst->qstride= src->qstride;
 +        dst->qscale= src->qscale;
 +    }
 +}
 +
 +//Exact copy of vf.c
 +void vf_next_draw_slice(struct vf_instance *vf,unsigned char** src, int * stride,int w, int h, int x, int y){
 +    if (vf->next->draw_slice) {
 +        vf->next->draw_slice(vf->next,src,stride,w,h,x,y);
 +        return;
 +    }
 +    if (!vf->dmpi) {
 +        mp_msg(MSGT_VFILTER,MSGL_ERR,"draw_slice: dmpi not stored by vf_%s\n", vf->info->name);
 +        return;
 +    }
 +    if (!(vf->dmpi->flags & MP_IMGFLAG_PLANAR)) {
 +        memcpy_pic(vf->dmpi->planes[0]+y*vf->dmpi->stride[0]+vf->dmpi->bpp/8*x,
 +            src[0], vf->dmpi->bpp/8*w, h, vf->dmpi->stride[0], stride[0]);
 +        return;
 +    }
 +    memcpy_pic(vf->dmpi->planes[0]+y*vf->dmpi->stride[0]+x, src[0],
 +        w, h, vf->dmpi->stride[0], stride[0]);
 +    memcpy_pic(vf->dmpi->planes[1]+(y>>vf->dmpi->chroma_y_shift)*vf->dmpi->stride[1]+(x>>vf->dmpi->chroma_x_shift),
 +        src[1], w>>vf->dmpi->chroma_x_shift, h>>vf->dmpi->chroma_y_shift, vf->dmpi->stride[1], stride[1]);
 +    memcpy_pic(vf->dmpi->planes[2]+(y>>vf->dmpi->chroma_y_shift)*vf->dmpi->stride[2]+(x>>vf->dmpi->chroma_x_shift),
 +        src[2], w>>vf->dmpi->chroma_x_shift, h>>vf->dmpi->chroma_y_shift, vf->dmpi->stride[2], stride[2]);
 +}
 +
 +//Exact copy of vf.c
 +void vf_mpi_clear(mp_image_t* mpi,int x0,int y0,int w,int h){
 +    int y;
 +    if(mpi->flags&MP_IMGFLAG_PLANAR){
 +        y0&=~1;h+=h&1;
 +        if(x0==0 && w==mpi->width){
 +            // full width clear:
 +            memset(mpi->planes[0]+mpi->stride[0]*y0,0,mpi->stride[0]*h);
 +            memset(mpi->planes[1]+mpi->stride[1]*(y0>>mpi->chroma_y_shift),128,mpi->stride[1]*(h>>mpi->chroma_y_shift));
 +            memset(mpi->planes[2]+mpi->stride[2]*(y0>>mpi->chroma_y_shift),128,mpi->stride[2]*(h>>mpi->chroma_y_shift));
 +        } else
 +        for(y=y0;y<y0+h;y+=2){
 +            memset(mpi->planes[0]+x0+mpi->stride[0]*y,0,w);
 +            memset(mpi->planes[0]+x0+mpi->stride[0]*(y+1),0,w);
 +            memset(mpi->planes[1]+(x0>>mpi->chroma_x_shift)+mpi->stride[1]*(y>>mpi->chroma_y_shift),128,(w>>mpi->chroma_x_shift));
 +            memset(mpi->planes[2]+(x0>>mpi->chroma_x_shift)+mpi->stride[2]*(y>>mpi->chroma_y_shift),128,(w>>mpi->chroma_x_shift));
 +        }
 +        return;
 +    }
 +    // packed:
 +    for(y=y0;y<y0+h;y++){
 +        unsigned char* dst=mpi->planes[0]+mpi->stride[0]*y+(mpi->bpp>>3)*x0;
 +        if(mpi->flags&MP_IMGFLAG_YUV){
 +            unsigned int* p=(unsigned int*) dst;
 +            int size=(mpi->bpp>>3)*w/4;
 +            int i;
 +#if HAVE_BIGENDIAN
 +#define CLEAR_PACKEDYUV_PATTERN 0x00800080
 +#define CLEAR_PACKEDYUV_PATTERN_SWAPPED 0x80008000
 +#else
 +#define CLEAR_PACKEDYUV_PATTERN 0x80008000
 +#define CLEAR_PACKEDYUV_PATTERN_SWAPPED 0x00800080
 +#endif
 +            if(mpi->flags&MP_IMGFLAG_SWAPPED){
 +                for(i=0;i<size-3;i+=4) p[i]=p[i+1]=p[i+2]=p[i+3]=CLEAR_PACKEDYUV_PATTERN_SWAPPED;
 +                for(;i<size;i++) p[i]=CLEAR_PACKEDYUV_PATTERN_SWAPPED;
 +            } else {
 +                for(i=0;i<size-3;i+=4) p[i]=p[i+1]=p[i+2]=p[i+3]=CLEAR_PACKEDYUV_PATTERN;
 +                for(;i<size;i++) p[i]=CLEAR_PACKEDYUV_PATTERN;
 +            }
 +        } else
 +            memset(dst,0,(mpi->bpp>>3)*w);
 +    }
 +}
 +
 +int vf_next_query_format(struct vf_instance *vf, unsigned int fmt){
 +    return 1;
 +}
 +
 +//used by delogo
 +unsigned int vf_match_csp(vf_instance_t** vfp,const unsigned int* list,unsigned int preferred){
 +    return preferred;
 +}
 +
 +mp_image_t* vf_get_image(vf_instance_t* vf, unsigned int outfmt, int mp_imgtype, int mp_imgflag, int w, int h){
 +    MPContext *m= (MPContext*)(((uint8_t*)vf) - offsetof(MPContext, next_vf));
 +  mp_image_t* mpi=NULL;
 +  int w2;
 +  int number = mp_imgtype >> 16;
 +
 +  av_assert0(vf->next == NULL); // all existing filters call this just on next
 +
 +  //vf_dint needs these as it calls vf_get_image() before configuring the output
 +  if(vf->w==0 && w>0) vf->w=w;
 +  if(vf->h==0 && h>0) vf->h=h;
 +
 +  av_assert0(w == -1 || w >= vf->w);
 +  av_assert0(h == -1 || h >= vf->h);
 +  av_assert0(vf->w > 0);
 +  av_assert0(vf->h > 0);
 +
 +  av_log(m->avfctx, AV_LOG_DEBUG, "get_image: %d:%d, vf: %d:%d\n", w,h,vf->w,vf->h);
 +
 +  if (w == -1) w = vf->w;
 +  if (h == -1) h = vf->h;
 +
 +  w2=(mp_imgflag&MP_IMGFLAG_ACCEPT_ALIGNED_STRIDE)?((w+15)&(~15)):w;
 +
 +  // Note: we should call libvo first to check if it supports direct rendering
 +  // and if not, then fallback to software buffers:
 +  switch(mp_imgtype & 0xff){
 +  case MP_IMGTYPE_EXPORT:
 +    if(!vf->imgctx.export_images[0]) vf->imgctx.export_images[0]=new_mp_image(w2,h);
 +    mpi=vf->imgctx.export_images[0];
 +    break;
 +  case MP_IMGTYPE_STATIC:
 +    if(!vf->imgctx.static_images[0]) vf->imgctx.static_images[0]=new_mp_image(w2,h);
 +    mpi=vf->imgctx.static_images[0];
 +    break;
 +  case MP_IMGTYPE_TEMP:
 +    if(!vf->imgctx.temp_images[0]) vf->imgctx.temp_images[0]=new_mp_image(w2,h);
 +    mpi=vf->imgctx.temp_images[0];
 +    break;
 +  case MP_IMGTYPE_IPB:
 +    if(!(mp_imgflag&MP_IMGFLAG_READABLE)){ // B frame:
 +      if(!vf->imgctx.temp_images[0]) vf->imgctx.temp_images[0]=new_mp_image(w2,h);
 +      mpi=vf->imgctx.temp_images[0];
 +      break;
 +    }
 +  case MP_IMGTYPE_IP:
 +    if(!vf->imgctx.static_images[vf->imgctx.static_idx]) vf->imgctx.static_images[vf->imgctx.static_idx]=new_mp_image(w2,h);
 +    mpi=vf->imgctx.static_images[vf->imgctx.static_idx];
 +    vf->imgctx.static_idx^=1;
 +    break;
 +  case MP_IMGTYPE_NUMBERED:
 +    if (number == -1) {
 +      int i;
 +      for (i = 0; i < NUM_NUMBERED_MPI; i++)
 +        if (!vf->imgctx.numbered_images[i] || !vf->imgctx.numbered_images[i]->usage_count)
 +          break;
 +      number = i;
 +    }
 +    if (number < 0 || number >= NUM_NUMBERED_MPI) return NULL;
 +    if (!vf->imgctx.numbered_images[number]) vf->imgctx.numbered_images[number] = new_mp_image(w2,h);
 +    mpi = vf->imgctx.numbered_images[number];
 +    mpi->number = number;
 +    break;
 +  }
 +  if(mpi){
 +    mpi->type=mp_imgtype;
 +    mpi->w=vf->w; mpi->h=vf->h;
 +    // keep buffer allocation status & color flags only:
 +//    mpi->flags&=~(MP_IMGFLAG_PRESERVE|MP_IMGFLAG_READABLE|MP_IMGFLAG_DIRECT);
 +    mpi->flags&=MP_IMGFLAG_ALLOCATED|MP_IMGFLAG_TYPE_DISPLAYED|MP_IMGFLAGMASK_COLORS;
 +    // accept restrictions, draw_slice and palette flags only:
 +    mpi->flags|=mp_imgflag&(MP_IMGFLAGMASK_RESTRICTIONS|MP_IMGFLAG_DRAW_CALLBACK|MP_IMGFLAG_RGB_PALETTE);
 +    if(!vf->draw_slice) mpi->flags&=~MP_IMGFLAG_DRAW_CALLBACK;
 +    if(mpi->width!=w2 || mpi->height!=h){
 +//      printf("vf.c: MPI parameters changed!  %dx%d -> %dx%d   \n", mpi->width,mpi->height,w2,h);
 +        if(mpi->flags&MP_IMGFLAG_ALLOCATED){
 +            if(mpi->width<w2 || mpi->height<h){
 +                // need to re-allocate buffer memory:
 +                av_free(mpi->planes[0]);
 +                mpi->flags&=~MP_IMGFLAG_ALLOCATED;
 +                mp_msg(MSGT_VFILTER,MSGL_V,"vf.c: have to REALLOCATE buffer memory :(\n");
 +            }
 +//      } else {
 +        } {
 +            mpi->width=w2; mpi->chroma_width=(w2 + (1<<mpi->chroma_x_shift) - 1)>>mpi->chroma_x_shift;
 +            mpi->height=h; mpi->chroma_height=(h + (1<<mpi->chroma_y_shift) - 1)>>mpi->chroma_y_shift;
 +        }
 +    }
 +    if(!mpi->bpp) mp_image_setfmt(mpi,outfmt);
 +    if(!(mpi->flags&MP_IMGFLAG_ALLOCATED) && mpi->type>MP_IMGTYPE_EXPORT){
 +
 +        av_assert0(!vf->get_image);
 +        // check libvo first!
 +        if(vf->get_image) vf->get_image(vf,mpi);
 +
 +        if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
 +          // non-direct and not yet allocated image. allocate it!
 +          if (!mpi->bpp) { // no way we can allocate this
 +              mp_msg(MSGT_DECVIDEO, MSGL_FATAL,
 +                     "vf_get_image: Tried to allocate a format that can not be allocated!\n");
 +              return NULL;
 +          }
 +
 +          // check if codec prefer aligned stride:
 +          if(mp_imgflag&MP_IMGFLAG_PREFER_ALIGNED_STRIDE){
 +              int align=(mpi->flags&MP_IMGFLAG_PLANAR &&
 +                         mpi->flags&MP_IMGFLAG_YUV) ?
 +                         (8<<mpi->chroma_x_shift)-1 : 15; // -- maybe FIXME
 +              w2=((w+align)&(~align));
 +              if(mpi->width!=w2){
 +#if 0
 +                  // we have to change width... check if we CAN co it:
 +                  int flags=vf->query_format(vf,outfmt); // should not fail
 +                  if(!(flags&3)) mp_msg(MSGT_DECVIDEO,MSGL_WARN,"??? vf_get_image{vf->query_format(outfmt)} failed!\n");
 +//                printf("query -> 0x%X    \n",flags);
 +                  if(flags&VFCAP_ACCEPT_STRIDE){
 +#endif
 +                      mpi->width=w2;
 +                      mpi->chroma_width=(w2 + (1<<mpi->chroma_x_shift) - 1)>>mpi->chroma_x_shift;
 +//                  }
 +              }
 +          }
 +
 +          mp_image_alloc_planes(mpi);
 +//        printf("clearing img!\n");
 +          vf_mpi_clear(mpi,0,0,mpi->width,mpi->height);
 +        }
 +    }
 +    av_assert0(!vf->start_slice);
 +    if(mpi->flags&MP_IMGFLAG_DRAW_CALLBACK)
 +        if(vf->start_slice) vf->start_slice(vf,mpi);
 +    if(!(mpi->flags&MP_IMGFLAG_TYPE_DISPLAYED)){
 +            mp_msg(MSGT_DECVIDEO,MSGL_V,"*** [%s] %s%s mp_image_t, %dx%dx%dbpp %s %s, %d bytes\n",
 +                  "NULL"/*vf->info->name*/,
 +                  (mpi->type==MP_IMGTYPE_EXPORT)?"Exporting":
 +                  ((mpi->flags&MP_IMGFLAG_DIRECT)?"Direct Rendering":"Allocating"),
 +                  (mpi->flags&MP_IMGFLAG_DRAW_CALLBACK)?" (slices)":"",
 +                  mpi->width,mpi->height,mpi->bpp,
 +                  (mpi->flags&MP_IMGFLAG_YUV)?"YUV":((mpi->flags&MP_IMGFLAG_SWAPPED)?"BGR":"RGB"),
 +                  (mpi->flags&MP_IMGFLAG_PLANAR)?"planar":"packed",
 +                  mpi->bpp*mpi->width*mpi->height/8);
 +            mp_msg(MSGT_DECVIDEO,MSGL_DBG2,"(imgfmt: %x, planes: %p,%p,%p strides: %d,%d,%d, chroma: %dx%d, shift: h:%d,v:%d)\n",
 +                mpi->imgfmt, mpi->planes[0], mpi->planes[1], mpi->planes[2],
 +                mpi->stride[0], mpi->stride[1], mpi->stride[2],
 +                mpi->chroma_width, mpi->chroma_height, mpi->chroma_x_shift, mpi->chroma_y_shift);
 +            mpi->flags|=MP_IMGFLAG_TYPE_DISPLAYED;
 +    }
 +
 +  mpi->qscale = NULL;
 +  }
 +  mpi->usage_count++;
 +//    printf("\rVF_MPI: %p %p %p %d %d %d    \n",
 +//      mpi->planes[0],mpi->planes[1],mpi->planes[2],
 +//      mpi->stride[0],mpi->stride[1],mpi->stride[2]);
 +  return mpi;
 +}
 +
 +
 +int vf_next_put_image(struct vf_instance *vf,mp_image_t *mpi, double pts){
 +    MPContext *m= (void*)vf;
 +    AVFilterLink *outlink     = m->avfctx->outputs[0];
 +    AVFilterBuffer    *pic    = av_mallocz(sizeof(AVFilterBuffer));
 +    AVFilterBufferRef *picref = av_mallocz(sizeof(AVFilterBufferRef));
 +    int i;
 +
 +    av_assert0(vf->next);
 +
 +    av_log(m->avfctx, AV_LOG_DEBUG, "vf_next_put_image\n");
 +
 +    if (!pic || !picref)
 +        goto fail;
 +
 +    picref->buf = pic;
 +    picref->buf->please_use_av_free= (void*)av_free;
 +    if (!(picref->video = av_mallocz(sizeof(AVFilterBufferRefVideoProps))))
 +        goto fail;
 +
 +    pic->w = picref->video->w = mpi->w;
 +    pic->h = picref->video->h = mpi->h;
 +
 +    /* make sure the buffer gets read permission or it's useless for output */
 +    picref->perms = AV_PERM_READ | AV_PERM_REUSE2;
 +//    av_assert0(mpi->flags&MP_IMGFLAG_READABLE);
 +    if(!(mpi->flags&MP_IMGFLAG_PRESERVE))
 +        picref->perms |= AV_PERM_WRITE;
 +
 +    pic->refcount = 1;
 +    picref->type = AVMEDIA_TYPE_VIDEO;
 +
 +    for(i=0; conversion_map[i].fmt && mpi->imgfmt != conversion_map[i].fmt; i++);
 +    pic->format = picref->format = conversion_map[i].pix_fmt;
 +
 +    memcpy(pic->data,        mpi->planes,   FFMIN(sizeof(pic->data)    , sizeof(mpi->planes)));
 +    memcpy(pic->linesize,    mpi->stride,   FFMIN(sizeof(pic->linesize), sizeof(mpi->stride)));
 +    memcpy(picref->data,     pic->data,     sizeof(picref->data));
 +    memcpy(picref->linesize, pic->linesize, sizeof(picref->linesize));
 +
 +    if(pts != MP_NOPTS_VALUE)
 +        picref->pts= pts * av_q2d(outlink->time_base);
 +
-                 avfilter_add_format(&avfmts, conversion_map[i].pix_fmt);
++    ff_start_frame(outlink, avfilter_ref_buffer(picref, ~0));
++    ff_draw_slice(outlink, 0, picref->video->h, 1);
++    ff_end_frame(outlink);
 +    avfilter_unref_buffer(picref);
 +    m->frame_returned++;
 +
 +    return 1;
 +fail:
 +    if (picref && picref->video)
 +        av_free(picref->video);
 +    av_free(picref);
 +    av_free(pic);
 +    return 0;
 +}
 +
 +int vf_next_config(struct vf_instance *vf,
 +        int width, int height, int d_width, int d_height,
 +        unsigned int voflags, unsigned int outfmt){
 +
 +    av_assert0(width>0 && height>0);
 +    vf->next->w = width; vf->next->h = height;
 +
 +    return 1;
 +#if 0
 +    int flags=vf->next->query_format(vf->next,outfmt);
 +    if(!flags){
 +        // hmm. colorspace mismatch!!!
 +        //this is fatal for us ATM
 +        return 0;
 +    }
 +    mp_msg(MSGT_VFILTER,MSGL_V,"REQ: flags=0x%X  req=0x%X  \n",flags,vf->default_reqs);
 +    miss=vf->default_reqs - (flags&vf->default_reqs);
 +    if(miss&VFCAP_ACCEPT_STRIDE){
 +        // vf requires stride support but vf->next doesn't support it!
 +        // let's insert the 'expand' filter, it does the job for us:
 +        vf_instance_t* vf2=vf_open_filter(vf->next,"expand",NULL);
 +        if(!vf2) return 0; // shouldn't happen!
 +        vf->next=vf2;
 +    }
 +    vf->next->w = width; vf->next->h = height;
 +#endif
 +    return 1;
 +}
 +
 +int vf_next_control(struct vf_instance *vf, int request, void* data){
 +    MPContext *m= (void*)vf;
 +    av_log(m->avfctx, AV_LOG_DEBUG, "Received control %d\n", request);
 +    return 0;
 +}
 +
 +static int vf_default_query_format(struct vf_instance *vf, unsigned int fmt){
 +    MPContext *m= (void*)vf;
 +    int i;
 +    av_log(m->avfctx, AV_LOG_DEBUG, "query %X\n", fmt);
 +
 +    for(i=0; conversion_map[i].fmt; i++){
 +        if(fmt==conversion_map[i].fmt)
 +            return 1; //we suport all
 +    }
 +    return 0;
 +}
 +
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
 +{
 +    MPContext *m = ctx->priv;
 +    char name[256];
 +    int i;
 +
 +    m->avfctx= ctx;
 +
 +    if(!args || 1!=sscanf(args, "%255[^:=]", name)){
 +        av_log(ctx, AV_LOG_ERROR, "Invalid parameter.\n");
 +        return AVERROR(EINVAL);
 +    }
 +    args+= strlen(name)+1;
 +
 +    for(i=0; ;i++){
 +        if(!filters[i] || !strcmp(name, filters[i]->name))
 +            break;
 +    }
 +
 +    if(!filters[i]){
 +        av_log(ctx, AV_LOG_ERROR, "Unknown filter %s\n", name);
 +        return AVERROR(EINVAL);
 +    }
 +
 +    av_log(ctx, AV_LOG_WARNING,
 +           "'%s' is a wrapped MPlayer filter (libmpcodecs). This filter may be removed\n"
 +           "once it has been ported to a native libavfilter.\n", name);
 +
 +    memset(&m->vf,0,sizeof(m->vf));
 +    m->vf.info= filters[i];
 +
 +    m->vf.next        = &m->next_vf;
 +    m->vf.put_image   = vf_next_put_image;
 +    m->vf.config      = vf_next_config;
 +    m->vf.query_format= vf_default_query_format;
 +    m->vf.control     = vf_next_control;
 +    m->vf.default_caps=VFCAP_ACCEPT_STRIDE;
 +    m->vf.default_reqs=0;
 +    if(m->vf.info->opts)
 +        av_log(ctx, AV_LOG_ERROR, "opts / m_struct_set is unsupported\n");
 +#if 0
 +    if(vf->info->opts) { // vf_vo get some special argument
 +      const m_struct_t* st = vf->info->opts;
 +      void* vf_priv = m_struct_alloc(st);
 +      int n;
 +      for(n = 0 ; args && args[2*n] ; n++)
 +        m_struct_set(st,vf_priv,args[2*n],args[2*n+1]);
 +      vf->priv = vf_priv;
 +      args = NULL;
 +    } else // Otherwise we should have the '_oldargs_'
 +      if(args && !strcmp(args[0],"_oldargs_"))
 +        args = (char**)args[1];
 +      else
 +        args = NULL;
 +#endif
 +    if(m->vf.info->vf_open(&m->vf, args)<=0){
 +        av_log(ctx, AV_LOG_ERROR, "vf_open() of %s with arg=%s failed\n", name, args);
 +        return -1;
 +    }
 +
 +    return 0;
 +}
 +
 +static av_cold void uninit(AVFilterContext *ctx)
 +{
 +    MPContext *m = ctx->priv;
 +    vf_instance_t *vf = &m->vf;
 +
 +    while(vf){
 +        vf_instance_t *next = vf->next;
 +        if(vf->uninit)
 +            vf->uninit(vf);
 +        free_mp_image(vf->imgctx.static_images[0]);
 +        free_mp_image(vf->imgctx.static_images[1]);
 +        free_mp_image(vf->imgctx.temp_images[0]);
 +        free_mp_image(vf->imgctx.export_images[0]);
 +        vf = next;
 +    }
 +}
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    AVFilterFormats *avfmts=NULL;
 +    MPContext *m = ctx->priv;
 +    enum PixelFormat lastpixfmt = PIX_FMT_NONE;
 +    int i;
 +
 +    for(i=0; conversion_map[i].fmt; i++){
 +        av_log(ctx, AV_LOG_DEBUG, "query: %X\n", conversion_map[i].fmt);
 +        if(m->vf.query_format(&m->vf, conversion_map[i].fmt)){
 +            av_log(ctx, AV_LOG_DEBUG, "supported,adding\n");
 +            if (conversion_map[i].pix_fmt != lastpixfmt) {
-     avfilter_set_common_pixel_formats(ctx, avfmts);
++                ff_add_format(&avfmts, conversion_map[i].pix_fmt);
 +                lastpixfmt = conversion_map[i].pix_fmt;
 +            }
 +        }
 +    }
 +
 +    //We assume all allowed input formats are also allowed output formats
-         ret=avfilter_request_frame(outlink->src->inputs[0]);
++    ff_set_common_formats(ctx, avfmts);
 +    return 0;
 +}
 +
 +static int config_inprops(AVFilterLink *inlink)
 +{
 +    MPContext *m = inlink->dst->priv;
 +    int i;
 +    for(i=0; conversion_map[i].fmt && conversion_map[i].pix_fmt != inlink->format; i++);
 +
 +    av_assert0(conversion_map[i].fmt && inlink->w && inlink->h);
 +
 +    m->vf.fmt.have_configured = 1;
 +    m->vf.fmt.orig_height     = inlink->h;
 +    m->vf.fmt.orig_width      = inlink->w;
 +    m->vf.fmt.orig_fmt        = conversion_map[i].fmt;
 +
 +    if(m->vf.config(&m->vf, inlink->w, inlink->h, inlink->w, inlink->h, 0, conversion_map[i].fmt)<=0)
 +        return -1;
 +
 +    return 0;
 +}
 +
 +static int config_outprops(AVFilterLink *outlink)
 +{
 +    MPContext *m = outlink->src->priv;
 +
 +    outlink->w = m->next_vf.w;
 +    outlink->h = m->next_vf.h;
 +
 +    return 0;
 +}
 +
 +static int request_frame(AVFilterLink *outlink)
 +{
 +    MPContext *m = outlink->src->priv;
 +    int ret;
 +
 +    av_log(m->avfctx, AV_LOG_DEBUG, "mp request_frame\n");
 +
 +    for(m->frame_returned=0; !m->frame_returned;){
++        ret=ff_request_frame(outlink->src->inputs[0]);
 +        if(ret<0)
 +            break;
 +    }
 +
 +    av_log(m->avfctx, AV_LOG_DEBUG, "mp request_frame ret=%d\n", ret);
 +    return ret;
 +}
 +
 +static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
 +{
 +}
 +
 +static void null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
 +{
 +}
 +
 +static void end_frame(AVFilterLink *inlink)
 +{
 +    MPContext *m = inlink->dst->priv;
 +    AVFilterBufferRef *inpic  = inlink->cur_buf;
 +    int i;
 +    double pts= MP_NOPTS_VALUE;
 +    mp_image_t* mpi = new_mp_image(inpic->video->w, inpic->video->h);
 +
 +    if(inpic->pts != AV_NOPTS_VALUE)
 +        pts= inpic->pts / av_q2d(inlink->time_base);
 +
 +    for(i=0; conversion_map[i].fmt && conversion_map[i].pix_fmt != inlink->format; i++);
 +    mp_image_setfmt(mpi,conversion_map[i].fmt);
 +
 +    memcpy(mpi->planes, inpic->data,     FFMIN(sizeof(inpic->data)    , sizeof(mpi->planes)));
 +    memcpy(mpi->stride, inpic->linesize, FFMIN(sizeof(inpic->linesize), sizeof(mpi->stride)));
 +
 +    //FIXME pass interleced & tff flags around
 +
 +    // mpi->flags|=MP_IMGFLAG_ALLOCATED; ?
 +    mpi->flags |= MP_IMGFLAG_READABLE;
 +    if(!(inpic->perms & AV_PERM_WRITE))
 +        mpi->flags |= MP_IMGFLAG_PRESERVE;
 +    if(m->vf.put_image(&m->vf, mpi, pts) == 0){
 +        av_log(m->avfctx, AV_LOG_DEBUG, "put_image() says skip\n");
 +    }
 +    free_mp_image(mpi);
 +
 +    avfilter_unref_buffer(inpic);
 +}
 +
 +AVFilter avfilter_vf_mp = {
 +    .name      = "mp",
 +    .description = NULL_IF_CONFIG_SMALL("Apply a libmpcodecs filter to the input video."),
 +    .init = init,
 +    .uninit = uninit,
 +    .priv_size = sizeof(MPContext),
 +    .query_formats = query_formats,
 +
 +    .inputs    = (const AVFilterPad[]) {{ .name      = "default",
 +                                    .type            = AVMEDIA_TYPE_VIDEO,
 +                                    .start_frame     = start_frame,
 +                                    .draw_slice      = null_draw_slice,
 +                                    .end_frame       = end_frame,
 +                                    .config_props    = config_inprops,
 +                                    .min_perms       = AV_PERM_READ, },
 +                                  { .name = NULL}},
 +    .outputs   = (const AVFilterPad[]) {{ .name      = "default",
 +                                    .type            = AVMEDIA_TYPE_VIDEO,
 +                                    .request_frame   = request_frame,
 +                                    .config_props    = config_outprops, },
 +                                  { .name = NULL}},
 +};
index 215f50a,0000000..45238b6
mode 100644,000000..100644
--- /dev/null
@@@ -1,244 -1,0 +1,244 @@@
-         int ret = avfilter_request_frame(link->src->inputs[0]);
 +/*
 + * Copyright (c) 2011 Smartjog S.A.S, Clément Bœsch <clement.boesch@smartjog.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
 + * Potential thumbnail lookup filter to reduce the risk of an inappropriate
 + * selection (such as a black frame) we could get with an absolute seek.
 + *
 + * Simplified version of algorithm by Vadim Zaliva <lord@crocodile.org>.
 + * @see http://notbrainsurgery.livejournal.com/29773.html
 + */
 +
 +#include "avfilter.h"
 +#include "internal.h"
 +
 +#define HIST_SIZE (3*256)
 +
 +struct thumb_frame {
 +    AVFilterBufferRef *buf;     ///< cached frame
 +    int histogram[HIST_SIZE];   ///< RGB color distribution histogram of the frame
 +};
 +
 +typedef struct {
 +    int n;                      ///< current frame
 +    int n_frames;               ///< number of frames for analysis
 +    struct thumb_frame *frames; ///< the n_frames frames
 +} ThumbContext;
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
 +{
 +    ThumbContext *thumb = ctx->priv;
 +
 +    if (!args) {
 +        thumb->n_frames = 100;
 +    } else {
 +        int n = sscanf(args, "%d", &thumb->n_frames);
 +        if (n != 1 || thumb->n_frames < 2) {
 +            thumb->n_frames = 0;
 +            av_log(ctx, AV_LOG_ERROR,
 +                   "Invalid number of frames specified (minimum is 2).\n");
 +            return AVERROR(EINVAL);
 +        }
 +    }
 +    thumb->frames = av_calloc(thumb->n_frames, sizeof(*thumb->frames));
 +    if (!thumb->frames) {
 +        av_log(ctx, AV_LOG_ERROR,
 +               "Allocation failure, try to lower the number of frames\n");
 +        return AVERROR(ENOMEM);
 +    }
 +    av_log(ctx, AV_LOG_INFO, "batch size: %d frames\n", thumb->n_frames);
 +    return 0;
 +}
 +
 +static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
 +{
 +    int i, j;
 +    AVFilterContext *ctx = inlink->dst;
 +    ThumbContext *thumb = ctx->priv;
 +    int *hist = thumb->frames[thumb->n].histogram;
 +    AVFilterBufferRef *picref = inlink->cur_buf;
 +    const uint8_t *p = picref->data[0] + y * picref->linesize[0];
 +
 +    // update current frame RGB histogram
 +    for (j = 0; j < h; j++) {
 +        for (i = 0; i < inlink->w; i++) {
 +            hist[0*256 + p[i*3    ]]++;
 +            hist[1*256 + p[i*3 + 1]]++;
 +            hist[2*256 + p[i*3 + 2]]++;
 +        }
 +        p += picref->linesize[0];
 +    }
 +}
 +
 +/**
 + * @brief        Compute Sum-square deviation to estimate "closeness".
 + * @param hist   color distribution histogram
 + * @param median average color distribution histogram
 + * @return       sum of squared errors
 + */
 +static double frame_sum_square_err(const int *hist, const double *median)
 +{
 +    int i;
 +    double err, sum_sq_err = 0;
 +
 +    for (i = 0; i < HIST_SIZE; i++) {
 +        err = median[i] - (double)hist[i];
 +        sum_sq_err += err*err;
 +    }
 +    return sum_sq_err;
 +}
 +
 +static void end_frame(AVFilterLink *inlink)
 +{
 +    int i, j, best_frame_idx = 0;
 +    double avg_hist[HIST_SIZE] = {0}, sq_err, min_sq_err = -1;
 +    AVFilterLink *outlink = inlink->dst->outputs[0];
 +    ThumbContext *thumb   = inlink->dst->priv;
 +    AVFilterContext *ctx  = inlink->dst;
 +    AVFilterBufferRef *picref;
 +
 +    // keep a reference of each frame
 +    thumb->frames[thumb->n].buf = inlink->cur_buf;
 +
 +    // no selection until the buffer of N frames is filled up
 +    if (thumb->n < thumb->n_frames - 1) {
 +        thumb->n++;
 +        return;
 +    }
 +
 +    // average histogram of the N frames
 +    for (j = 0; j < FF_ARRAY_ELEMS(avg_hist); j++) {
 +        for (i = 0; i < thumb->n_frames; i++)
 +            avg_hist[j] += (double)thumb->frames[i].histogram[j];
 +        avg_hist[j] /= thumb->n_frames;
 +    }
 +
 +    // find the frame closer to the average using the sum of squared errors
 +    for (i = 0; i < thumb->n_frames; i++) {
 +        sq_err = frame_sum_square_err(thumb->frames[i].histogram, avg_hist);
 +        if (i == 0 || sq_err < min_sq_err)
 +            best_frame_idx = i, min_sq_err = sq_err;
 +    }
 +
 +    // free and reset everything (except the best frame buffer)
 +    for (i = 0; i < thumb->n_frames; i++) {
 +        memset(thumb->frames[i].histogram, 0, sizeof(thumb->frames[i].histogram));
 +        if (i == best_frame_idx)
 +            continue;
 +        avfilter_unref_buffer(thumb->frames[i].buf);
 +        thumb->frames[i].buf = NULL;
 +    }
 +    thumb->n = 0;
 +
 +    // raise the chosen one
 +    picref = thumb->frames[best_frame_idx].buf;
 +    av_log(ctx, AV_LOG_INFO, "frame id #%d (pts_time=%f) selected\n",
 +           best_frame_idx, picref->pts * av_q2d(inlink->time_base));
 +    ff_start_frame(outlink, picref);
 +    thumb->frames[best_frame_idx].buf = NULL;
 +    ff_draw_slice(outlink, 0, inlink->h, 1);
 +    ff_end_frame(outlink);
 +}
 +
 +static av_cold void uninit(AVFilterContext *ctx)
 +{
 +    int i;
 +    ThumbContext *thumb = ctx->priv;
 +    for (i = 0; i < thumb->n_frames && thumb->frames[i].buf; i++) {
 +        avfilter_unref_buffer(thumb->frames[i].buf);
 +        thumb->frames[i].buf = NULL;
 +    }
 +    av_freep(&thumb->frames);
 +}
 +
 +static void null_start_frame(AVFilterLink *link, AVFilterBufferRef *picref) { }
 +
 +static int request_frame(AVFilterLink *link)
 +{
 +    ThumbContext *thumb = link->src->priv;
 +
 +    /* loop until a frame thumbnail is available (when a frame is queued,
 +     * thumb->n is reset to zero) */
 +    do {
-     ret = avfilter_request_frame(inlink);
++        int ret = ff_request_frame(link->src->inputs[0]);
 +        if (ret < 0)
 +            return ret;
 +    } while (thumb->n);
 +    return 0;
 +}
 +
 +static int poll_frame(AVFilterLink *link)
 +{
 +    ThumbContext *thumb  = link->src->priv;
 +    AVFilterLink *inlink = link->src->inputs[0];
 +    int ret, available_frames = ff_poll_frame(inlink);
 +
 +    /* If the input link is not able to provide any frame, we can't do anything
 +     * at the moment and thus have zero thumbnail available. */
 +    if (!available_frames)
 +        return 0;
 +
 +    /* Since at least one frame is available and the next frame will allow us
 +     * to compute a thumbnail, we can return 1 frame. */
 +    if (thumb->n == thumb->n_frames - 1)
 +        return 1;
 +
 +    /* we have some frame(s) available in the input link, but not yet enough to
 +     * output a thumbnail, so we request more */
++    ret = ff_request_frame(inlink);
 +    return ret < 0 ? ret : 0;
 +}
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    static const enum PixelFormat pix_fmts[] = {
 +        PIX_FMT_RGB24, PIX_FMT_BGR24,
 +        PIX_FMT_NONE
 +    };
 +    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
 +    return 0;
 +}
 +
 +AVFilter avfilter_vf_thumbnail = {
 +    .name          = "thumbnail",
 +    .description   = NULL_IF_CONFIG_SMALL("Select the most representative frame in a given sequence of consecutive frames."),
 +    .priv_size     = sizeof(ThumbContext),
 +    .init          = init,
 +    .uninit        = uninit,
 +    .query_formats = query_formats,
 +    .inputs        = (const AVFilterPad[]) {
 +        {   .name             = "default",
 +            .type             = AVMEDIA_TYPE_VIDEO,
 +            .get_video_buffer = ff_null_get_video_buffer,
 +            .start_frame      = null_start_frame,
 +            .draw_slice       = draw_slice,
 +            .end_frame        = end_frame,
 +        },{ .name = NULL }
 +    },
 +    .outputs       = (const AVFilterPad[]) {
 +        {   .name             = "default",
 +            .type             = AVMEDIA_TYPE_VIDEO,
 +            .request_frame    = request_frame,
 +            .poll_frame       = poll_frame,
 +            .rej_perms        = AV_PERM_REUSE2,
 +        },{ .name = NULL }
 +    },
 +};
index e6971de,0000000..83ee45d
mode 100644,000000..100644
--- /dev/null
@@@ -1,210 -1,0 +1,211 @@@
-         r = avfilter_request_frame(inlink);
 +/*
 + * Copyright (c) 2012 Nicolas George
 + *
 + * 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
 + * tile video filter
 + */
 +
 +#include "libavutil/pixdesc.h"
 +#include "avfilter.h"
 +#include "drawutils.h"
 +#include "formats.h"
 +#include "video.h"
++#include "internal.h"
 +
 +typedef struct {
 +    unsigned w, h;
 +    unsigned current;
 +    FFDrawContext draw;
 +    FFDrawColor blank;
 +} TileContext;
 +
 +#define REASONABLE_SIZE 1024
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
 +{
 +    TileContext *tile = ctx->priv;
 +    int r;
 +    char dummy;
 +
 +    if (!args)
 +        args = "6x5";
 +    r = sscanf(args, "%ux%u%c", &tile->w, &tile->h, &dummy);
 +    if (r != 2 || !tile->w || !tile->h)
 +        return AVERROR(EINVAL);
 +    if (tile->w > REASONABLE_SIZE || tile->h > REASONABLE_SIZE) {
 +        av_log(ctx, AV_LOG_ERROR, "Tile size %ux%u is insane.\n",
 +               tile->w, tile->h);
 +        return AVERROR(EINVAL);
 +    }
 +    return 0;
 +}
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
 +    return 0;
 +}
 +
 +static int config_props(AVFilterLink *outlink)
 +{
 +    AVFilterContext *ctx = outlink->src;
 +    TileContext *tile   = ctx->priv;
 +    AVFilterLink *inlink = ctx->inputs[0];
 +
 +    if (inlink->w > INT_MAX / tile->w) {
 +        av_log(ctx, AV_LOG_ERROR, "Total width %ux%u is too much.\n",
 +               tile->w, inlink->w);
 +        return AVERROR(EINVAL);
 +    }
 +    if (inlink->h > INT_MAX / tile->h) {
 +        av_log(ctx, AV_LOG_ERROR, "Total height %ux%u is too much.\n",
 +               tile->h, inlink->h);
 +        return AVERROR(EINVAL);
 +    }
 +    outlink->w = tile->w * inlink->w;
 +    outlink->h = tile->h * inlink->h;
 +    outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
 +    outlink->frame_rate = av_mul_q(inlink->frame_rate,
 +                                   (AVRational){ 1, tile->w * tile->h });
 +    ff_draw_init(&tile->draw, inlink->format, 0);
 +    /* TODO make the color an option, or find an unified way of choosing it */
 +    ff_draw_color(&tile->draw, &tile->blank, (uint8_t[]){ 0, 0, 0, -1 });
 +
 +    return 0;
 +}
 +
 +/* Note: direct rendering is not possible since there is no guarantee that
 + * buffers are fed to start_frame in the order they were obtained from
 + * get_buffer (think B-frames). */
 +
 +static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
 +{
 +    AVFilterContext *ctx  = inlink->dst;
 +    TileContext *tile    = ctx->priv;
 +    AVFilterLink *outlink = ctx->outputs[0];
 +
 +    if (tile->current)
 +        return;
 +    outlink->out_buf = ff_get_video_buffer(outlink, AV_PERM_WRITE,
 +                                                 outlink->w, outlink->h);
 +    avfilter_copy_buffer_ref_props(outlink->out_buf, picref);
 +    outlink->out_buf->video->w = outlink->w;
 +    outlink->out_buf->video->h = outlink->h;
 +    ff_start_frame(outlink, outlink->out_buf);
 +}
 +
 +static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
 +{
 +    AVFilterContext *ctx  = inlink->dst;
 +    TileContext *tile    = ctx->priv;
 +    AVFilterLink *outlink = ctx->outputs[0];
 +    unsigned x0 = inlink->w * (tile->current % tile->w);
 +    unsigned y0 = inlink->h * (tile->current / tile->w);
 +
 +    ff_copy_rectangle2(&tile->draw,
 +                       outlink->out_buf->data, outlink->out_buf->linesize,
 +                       inlink ->cur_buf->data, inlink ->cur_buf->linesize,
 +                       x0, y0 + y, 0, y, inlink->cur_buf->video->w, h);
 +    /* TODO if tile->w == 1 && slice_dir is always 1, we could draw_slice
 +     * immediately. */
 +}
 +
 +static void draw_blank_frame(AVFilterContext *ctx)
 +{
 +    TileContext *tile    = ctx->priv;
 +    AVFilterLink *inlink  = ctx->inputs[0];
 +    AVFilterLink *outlink = ctx->outputs[0];
 +    unsigned x0 = inlink->w * (tile->current % tile->w);
 +    unsigned y0 = inlink->h * (tile->current / tile->w);
 +
 +    ff_fill_rectangle(&tile->draw, &tile->blank,
 +                      outlink->out_buf->data, outlink->out_buf->linesize,
 +                      x0, y0, inlink->w, inlink->h);
 +    tile->current++;
 +}
 +static void end_last_frame(AVFilterContext *ctx)
 +{
 +    TileContext *tile    = ctx->priv;
 +    AVFilterLink *outlink = ctx->outputs[0];
 +
 +    while (tile->current < tile->w * tile->h)
 +        draw_blank_frame(ctx);
 +    ff_draw_slice(outlink, 0, outlink->out_buf->video->h, 1);
 +    ff_end_frame(outlink);
 +    tile->current = 0;
 +}
 +
 +static void end_frame(AVFilterLink *inlink)
 +{
 +    AVFilterContext *ctx  = inlink->dst;
 +    TileContext *tile    = ctx->priv;
 +
 +    avfilter_unref_buffer(inlink->cur_buf);
 +    if (++tile->current == tile->w * tile->h)
 +        end_last_frame(ctx);
 +}
 +
 +static int request_frame(AVFilterLink *outlink)
 +{
 +    AVFilterContext *ctx = outlink->src;
 +    TileContext *tile   = ctx->priv;
 +    AVFilterLink *inlink = ctx->inputs[0];
 +    int r;
 +
 +    while (1) {
++        r = ff_request_frame(inlink);
 +        if (r < 0) {
 +            if (r == AVERROR_EOF && tile->current)
 +                end_last_frame(ctx);
 +            else
 +                return r;
 +            break;
 +        }
 +        if (!tile->current) /* done */
 +            break;
 +    }
 +    return 0;
 +}
 +
 +
 +AVFilter avfilter_vf_tile = {
 +    .name          = "tile",
 +    .description   = NULL_IF_CONFIG_SMALL("Tile several successive frames together."),
 +    .init          = init,
 +    .query_formats = query_formats,
 +    .priv_size     = sizeof(TileContext),
 +    .inputs = (const AVFilterPad[]) {
 +        { .name        = "default",
 +          .type        = AVMEDIA_TYPE_VIDEO,
 +          .start_frame = start_frame,
 +          .draw_slice  = draw_slice,
 +          .end_frame   = end_frame,
 +          .min_perms   = AV_PERM_READ, },
 +        { .name = NULL }
 +    },
 +    .outputs = (const AVFilterPad[]) {
 +        { .name          = "default",
 +          .type          = AVMEDIA_TYPE_VIDEO,
 +          .config_props  = config_props,
 +          .request_frame = request_frame },
 +        { .name = NULL }
 +    },
 +};
index 8f9dc00,0000000..b0d04eb
mode 100644,000000..100644
--- /dev/null
@@@ -1,387 -1,0 +1,387 @@@
-         if ((ret = avfilter_request_frame(inlink)) < 0)
 +/*
 + * Copyright (c) 2011 Stefano Sabatini
 + * Copyright (c) 2010 Baptiste Coudurier
 + * Copyright (c) 2003 Michael Zucchi <notzed@ximian.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 General Public License as published by
 + * the Free Software Foundation; either version 2 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 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
 + * temporal field interlace filter, ported from MPlayer/libmpcodecs
 + */
 +
 +#include "libavutil/imgutils.h"
 +#include "avfilter.h"
 +#include "internal.h"
 +
 +enum TInterlaceMode {
 +    MODE_MERGE = 0,
 +    MODE_DROP_EVEN,
 +    MODE_DROP_ODD,
 +    MODE_PAD,
 +    MODE_INTERLEAVE_TOP,
 +    MODE_INTERLEAVE_BOTTOM,
 +    MODE_INTERLACEX2,
 +};
 +
 +static const char *tinterlace_mode_str[] = {
 +    "merge",
 +    "drop_even",
 +    "drop_odd",
 +    "pad",
 +    "interleave_top",
 +    "interleave_bottom",
 +    "interlacex2",
 +    NULL
 +};
 +
 +typedef struct {
 +    enum TInterlaceMode mode;   ///< interlace mode selected
 +    int frame;                  ///< number of the output frame
 +    int vsub;                   ///< chroma vertical subsampling
 +    AVFilterBufferRef *cur;
 +    AVFilterBufferRef *next;
 +    uint8_t *black_data[4];     ///< buffer used to fill padded lines
 +    int black_linesize[4];
 +} TInterlaceContext;
 +
 +#define FULL_SCALE_YUVJ_FORMATS \
 +    PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ444P, PIX_FMT_YUVJ440P
 +
 +static enum PixelFormat full_scale_yuvj_pix_fmts[] = {
 +    FULL_SCALE_YUVJ_FORMATS, PIX_FMT_NONE
 +};
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    static const enum PixelFormat pix_fmts[] = {
 +        PIX_FMT_YUV420P,  PIX_FMT_YUV422P,  PIX_FMT_YUV444P,
 +        PIX_FMT_YUV444P,  PIX_FMT_YUV410P,  PIX_FMT_YUVA420P,
 +        PIX_FMT_GRAY8, FULL_SCALE_YUVJ_FORMATS,
 +        PIX_FMT_NONE
 +    };
 +
 +    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
 +    return 0;
 +}
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
 +{
 +    TInterlaceContext *tinterlace = ctx->priv;
 +    int i;
 +    char c;
 +
 +    tinterlace->mode = MODE_MERGE;
 +
 +    if (args) {
 +        if (sscanf(args, "%d%c", (int *)&tinterlace->mode, &c) == 1) {
 +            if (tinterlace->mode > 6) {
 +                av_log(ctx, AV_LOG_ERROR,
 +                       "Invalid mode '%s', use an integer between 0 and 6\n", args);
 +                return AVERROR(EINVAL);
 +            }
 +
 +            av_log(ctx, AV_LOG_WARNING,
 +                   "Using numeric constant is deprecated, use symbolic values\n");
 +        } else {
 +            for (i = 0; tinterlace_mode_str[i]; i++) {
 +                if (!strcmp(tinterlace_mode_str[i], args)) {
 +                    tinterlace->mode = i;
 +                    break;
 +                }
 +            }
 +            if (!tinterlace_mode_str[i]) {
 +                av_log(ctx, AV_LOG_ERROR, "Invalid argument '%s'\n", args);
 +                return AVERROR(EINVAL);
 +            }
 +        }
 +    }
 +
 +    return 0;
 +}
 +
 +static av_cold void uninit(AVFilterContext *ctx)
 +{
 +    TInterlaceContext *tinterlace = ctx->priv;
 +
 +    if (tinterlace->cur ) avfilter_unref_bufferp(&tinterlace->cur );
 +    if (tinterlace->next) avfilter_unref_bufferp(&tinterlace->next);
 +
 +    av_freep(&tinterlace->black_data[0]);
 +}
 +
 +static int config_out_props(AVFilterLink *outlink)
 +{
 +    AVFilterContext *ctx = outlink->src;
 +    AVFilterLink *inlink = outlink->src->inputs[0];
 +    const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[outlink->format];
 +    TInterlaceContext *tinterlace = ctx->priv;
 +
 +    tinterlace->vsub = desc->log2_chroma_h;
 +    outlink->w = inlink->w;
 +    outlink->h = tinterlace->mode == MODE_MERGE || tinterlace->mode == MODE_PAD ?
 +        inlink->h*2 : inlink->h;
 +
 +    if (tinterlace->mode == MODE_PAD) {
 +        uint8_t black[4] = { 16, 128, 128, 16 };
 +        int i, ret;
 +        if (ff_fmt_is_in(outlink->format, full_scale_yuvj_pix_fmts))
 +            black[0] = black[3] = 0;
 +        ret = av_image_alloc(tinterlace->black_data, tinterlace->black_linesize,
 +                             outlink->w, outlink->h, outlink->format, 1);
 +        if (ret < 0)
 +            return ret;
 +
 +        /* fill black picture with black */
 +        for (i = 0; i < 4 && tinterlace->black_data[i]; i++) {
 +            int h = i == 1 || i == 2 ? outlink->h >> desc->log2_chroma_h : outlink->h;
 +            memset(tinterlace->black_data[i], black[i],
 +                   tinterlace->black_linesize[i] * h);
 +        }
 +    }
 +    av_log(ctx, AV_LOG_INFO, "mode:%s h:%d -> h:%d\n",
 +           tinterlace_mode_str[tinterlace->mode], inlink->h, outlink->h);
 +
 +    return 0;
 +}
 +
 +#define FIELD_UPPER           0
 +#define FIELD_LOWER           1
 +#define FIELD_UPPER_AND_LOWER 2
 +
 +/**
 + * Copy picture field from src to dst.
 + *
 + * @param src_field copy from upper, lower field or both
 + * @param interleave leave a padding line between each copied line
 + * @param dst_field copy to upper or lower field,
 + *        only meaningful when interleave is selected
 + */
 +static inline
 +void copy_picture_field(uint8_t *dst[4], int dst_linesize[4],
 +                        uint8_t *src[4], int src_linesize[4],
 +                        enum PixelFormat format, int w, int src_h,
 +                        int src_field, int interleave, int dst_field)
 +{
 +    const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[format];
 +    int plane, vsub = desc->log2_chroma_h;
 +    int k = src_field == FIELD_UPPER_AND_LOWER ? 1 : 2;
 +
 +    for (plane = 0; plane < desc->nb_components; plane++) {
 +        int lines = plane == 1 || plane == 2 ? src_h >> vsub : src_h;
 +        int linesize = av_image_get_linesize(format, w, plane);
 +        uint8_t *dstp = dst[plane];
 +        uint8_t *srcp = src[plane];
 +        lines /= k;
 +        if (src_field == FIELD_LOWER)
 +            srcp += src_linesize[plane];
 +        if (interleave && dst_field == FIELD_LOWER)
 +            dstp += dst_linesize[plane];
 +        av_image_copy_plane(dstp, dst_linesize[plane] * (interleave ? 2 : 1),
 +                            srcp, src_linesize[plane]*k, linesize, lines);
 +    }
 +}
 +
 +static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
 +{
 +    AVFilterContext *ctx = inlink->dst;
 +    TInterlaceContext *tinterlace = ctx->priv;
 +
 +    avfilter_unref_buffer(tinterlace->cur);
 +    tinterlace->cur  = tinterlace->next;
 +    tinterlace->next = picref;
 +}
 +
 +static void end_frame(AVFilterLink *inlink)
 +{
 +    AVFilterContext *ctx = inlink->dst;
 +    AVFilterLink *outlink = ctx->outputs[0];
 +    TInterlaceContext *tinterlace = ctx->priv;
 +    AVFilterBufferRef *cur  = tinterlace->cur;
 +    AVFilterBufferRef *next = tinterlace->next;
 +    AVFilterBufferRef *out  = NULL;
 +    int field, tff;
 +
 +    /* we need at least two frames */
 +    if (!tinterlace->cur)
 +        return;
 +
 +    switch (tinterlace->mode) {
 +    case MODE_MERGE: /* move the odd frame into the upper field of the new image, even into
 +             * the lower field, generating a double-height video at half framerate */
 +        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
 +        avfilter_copy_buffer_ref_props(out, cur);
 +        out->video->h = outlink->h;
 +        out->video->interlaced = 1;
 +        out->video->top_field_first = 1;
 +
 +        /* write odd frame lines into the upper field of the new frame */
 +        copy_picture_field(out->data, out->linesize,
 +                           cur->data, cur->linesize,
 +                           inlink->format, inlink->w, inlink->h,
 +                           FIELD_UPPER_AND_LOWER, 1, FIELD_UPPER);
 +        /* write even frame lines into the lower field of the new frame */
 +        copy_picture_field(out->data, out->linesize,
 +                           next->data, next->linesize,
 +                           inlink->format, inlink->w, inlink->h,
 +                           FIELD_UPPER_AND_LOWER, 1, FIELD_LOWER);
 +        avfilter_unref_bufferp(&tinterlace->next);
 +        break;
 +
 +    case MODE_DROP_ODD:  /* only output even frames, odd  frames are dropped; height unchanged, half framerate */
 +    case MODE_DROP_EVEN: /* only output odd  frames, even frames are dropped; height unchanged, half framerate */
 +        out = avfilter_ref_buffer(tinterlace->mode == MODE_DROP_EVEN ? cur : next, AV_PERM_READ);
 +        avfilter_unref_bufferp(&tinterlace->next);
 +        break;
 +
 +    case MODE_PAD: /* expand each frame to double height, but pad alternate
 +                    * lines with black; framerate unchanged */
 +        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
 +        avfilter_copy_buffer_ref_props(out, cur);
 +        out->video->h = outlink->h;
 +
 +        field = (1 + tinterlace->frame) & 1 ? FIELD_UPPER : FIELD_LOWER;
 +        /* copy upper and lower fields */
 +        copy_picture_field(out->data, out->linesize,
 +                           cur->data, cur->linesize,
 +                           inlink->format, inlink->w, inlink->h,
 +                           FIELD_UPPER_AND_LOWER, 1, field);
 +        /* pad with black the other field */
 +        copy_picture_field(out->data, out->linesize,
 +                           tinterlace->black_data, tinterlace->black_linesize,
 +                           inlink->format, inlink->w, inlink->h,
 +                           FIELD_UPPER_AND_LOWER, 1, !field);
 +        break;
 +
 +        /* interleave upper/lower lines from odd frames with lower/upper lines from even frames,
 +         * halving the frame rate and preserving image height */
 +    case MODE_INTERLEAVE_TOP:    /* top    field first */
 +    case MODE_INTERLEAVE_BOTTOM: /* bottom field first */
 +        tff = tinterlace->mode == MODE_INTERLEAVE_TOP;
 +        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
 +        avfilter_copy_buffer_ref_props(out, cur);
 +        out->video->interlaced = 1;
 +        out->video->top_field_first = tff;
 +
 +        /* copy upper/lower field from cur */
 +        copy_picture_field(out->data, out->linesize,
 +                           cur->data, cur->linesize,
 +                           inlink->format, inlink->w, inlink->h,
 +                           tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER);
 +        /* copy lower/upper field from next */
 +        copy_picture_field(out->data, out->linesize,
 +                           next->data, next->linesize,
 +                           inlink->format, inlink->w, inlink->h,
 +                           tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER);
 +        avfilter_unref_bufferp(&tinterlace->next);
 +        break;
 +    case MODE_INTERLACEX2: /* re-interlace preserving image height, double frame rate */
 +        /* output current frame first */
 +        out = avfilter_ref_buffer(cur, AV_PERM_READ);
 +        out->video->interlaced = 1;
 +
 +        ff_start_frame(outlink, out);
 +        ff_draw_slice(outlink, 0, outlink->h, 1);
 +        ff_end_frame(outlink);
 +
 +        /* output mix of current and next frame */
 +        tff = next->video->top_field_first;
 +        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
 +        avfilter_copy_buffer_ref_props(out, next);
 +        out->video->interlaced = 1;
 +
 +        /* write current frame second field lines into the second field of the new frame */
 +        copy_picture_field(out->data, out->linesize,
 +                           cur->data, cur->linesize,
 +                           inlink->format, inlink->w, inlink->h,
 +                           tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER);
 +        /* write next frame first field lines into the first field of the new frame */
 +        copy_picture_field(out->data, out->linesize,
 +                           next->data, next->linesize,
 +                           inlink->format, inlink->w, inlink->h,
 +                           tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER);
 +        break;
 +    }
 +
 +    ff_start_frame(outlink, out);
 +    ff_draw_slice(outlink, 0, outlink->h, 1);
 +    ff_end_frame(outlink);
 +
 +    tinterlace->frame++;
 +}
 +
 +static int poll_frame(AVFilterLink *outlink)
 +{
 +    TInterlaceContext *tinterlace = outlink->src->priv;
 +    AVFilterLink *inlink = outlink->src->inputs[0];
 +    int ret, val;
 +
 +    val = ff_poll_frame(inlink);
 +
 +    if (val == 1 && !tinterlace->next) {
-         if ((ret = avfilter_request_frame(inlink)) < 0)
++        if ((ret = ff_request_frame(inlink)) < 0)
 +            return ret;
 +        val = ff_poll_frame(inlink);
 +    }
 +    assert(tinterlace->next);
 +
 +    return val;
 +}
 +
 +static int request_frame(AVFilterLink *outlink)
 +{
 +    TInterlaceContext *tinterlace = outlink->src->priv;
 +    AVFilterLink *inlink = outlink->src->inputs[0];
 +
 +    do {
 +        int ret;
 +
++        if ((ret = ff_request_frame(inlink)) < 0)
 +            return ret;
 +    } while (!tinterlace->cur);
 +
 +    return 0;
 +}
 +
 +static void null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) { }
 +
 +AVFilter avfilter_vf_tinterlace = {
 +    .name          = "tinterlace",
 +    .description   = NULL_IF_CONFIG_SMALL("Perform temporal field interlacing."),
 +    .priv_size     = sizeof(TInterlaceContext),
 +    .init          = init,
 +    .uninit        = uninit,
 +    .query_formats = query_formats,
 +
 +    .inputs = (const AVFilterPad[]) {
 +        { .name          = "default",
 +          .type          = AVMEDIA_TYPE_VIDEO,
 +          .start_frame   = start_frame,
 +          .draw_slice    = null_draw_slice,
 +          .end_frame     = end_frame, },
 +        { .name = NULL}
 +    },
 +    .outputs = (const AVFilterPad[]) {
 +        { .name          = "default",
 +          .type          = AVMEDIA_TYPE_VIDEO,
 +          .config_props  = config_out_props,
 +          .poll_frame    = poll_frame,
 +          .request_frame = request_frame },
 +        { .name = NULL}
 +    },
 +};
@@@ -321,6 -309,6 +321,11 @@@ void ff_draw_slice(AVFilterLink *link, 
      draw_slice(link, y, h, slice_dir);
  }
  
++void avfilter_default_end_frame(AVFilterLink *inlink)
++{
++    default_end_frame(inlink);
++}
++
  #if FF_API_FILTERS_PUBLIC
  AVFilterBufferRef *avfilter_default_get_video_buffer(AVFilterLink *link, int perms, int w, int h)
  {
@@@ -330,10 -318,10 +335,6 @@@ void avfilter_default_start_frame(AVFil
  {
      default_start_frame(inlink, picref);
  }
--void avfilter_default_end_frame(AVFilterLink *inlink)
--{
--    default_end_frame(inlink);
--}
  void avfilter_default_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
  {
      default_draw_slice(inlink, y, h, slice_dir);
diff --cc libavutil/cpu.c
Simple merge
diff --cc libavutil/cpu.h
  #define AV_CPU_FLAG_SSE4         0x0100 ///< Penryn SSE4.1 functions
  #define AV_CPU_FLAG_SSE42        0x0200 ///< Nehalem SSE4.2 functions
  #define AV_CPU_FLAG_AVX          0x4000 ///< AVX functions: requires OS support even if YMM registers aren't used
- #define AV_CPU_FLAG_CMOV      0x1000000 ///< supports cmov instruction
  #define AV_CPU_FLAG_XOP          0x0400 ///< Bulldozer XOP functions
  #define AV_CPU_FLAG_FMA4         0x0800 ///< Bulldozer FMA4 functions
 -#define AV_CPU_FLAG_CMOV         0x1000 ///< i686 cmov
++#if LIBAVUTIL_VERSION_MAJOR <52
++#define AV_CPU_FLAG_CMOV      0x1001000 ///< supports cmov instruction
++#else
++#define AV_CPU_FLAG_CMOV         0x1000 ///< supports cmov instruction
++#endif
  #define AV_CPU_FLAG_ALTIVEC      0x0001 ///< standard
  
  #define AV_CPU_FLAG_ARMV5TE      (1 << 0)
Simple merge