Merge commit '95f1f56a21bc2f824af6fb97ca7ab35cdd0c401e'
authorMichael Niedermayer <michaelni@gmx.at>
Wed, 10 Apr 2013 21:18:18 +0000 (23:18 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Wed, 10 Apr 2013 21:24:48 +0000 (23:24 +0200)
* commit '95f1f56a21bc2f824af6fb97ca7ab35cdd0c401e':
  vf_select: switch to an AVOptions-based system.

Conflicts:
doc/filters.texi
libavfilter/f_select.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
doc/filters.texi
libavfilter/avfilter.c
libavfilter/f_select.c

@@@ -6067,368 -1489,269 +6067,370 @@@ This source accepts the following optio
  
  @table @option
  
 -@item x
 -The horizontal position of the left edge of the overlaid video on the main video.
 +@item size
 +The size of the video to generate, may be a string of the form
 +@var{width}x@var{height} or a frame size abbreviation.
  
 -@item y
 -The vertical position of the top edge of the overlaid video on the main video.
 +@item framerate
 +Framerate of the generated video, may be a string of the form
 +@var{num}/@var{den} or a frame rate abbreviation.
  
 -@end table
 +@item filter_name
 +The name to the frei0r source to load. For more information regarding frei0r and
 +how to set the parameters read the section @ref{frei0r} in the description of
 +the video filters.
  
 -The parameters are expressions containing the following parameters:
 +@item filter_params
 +A '|'-separated list of parameters to pass to the frei0r source.
  
 -@table @option
 -@item main_w, main_h
 -main input width and height
 +@end table
  
 -@item W, H
 -same as @var{main_w} and @var{main_h}
 +For example, to generate a frei0r partik0l source with size 200x200
 +and frame rate 10 which is overlayed on the overlay filter main input:
 +@example
 +frei0r_src=size=200x200:framerate=10:filter_name=partik0l:filter_params=1234 [overlay]; [in][overlay] overlay
 +@end example
  
 -@item overlay_w, overlay_h
 -overlay input width and height
 +@section life
  
 -@item w, h
 -same as @var{overlay_w} and @var{overlay_h}
 -@end table
 +Generate a life pattern.
  
 -Be aware that frames are taken from each input video in timestamp
 -order, hence, if their initial timestamps differ, it is a a good idea
 -to pass the two inputs through a @var{setpts=PTS-STARTPTS} filter to
 -have them begin in the same zero timestamp, as it does the example for
 -the @var{movie} filter.
 +This source is based on a generalization of John Conway's life game.
  
 -Follow some examples:
 -@example
 -# draw the overlay at 10 pixels from the bottom right
 -# corner of the main video.
 -overlay=x=main_w-overlay_w-10:y=main_h-overlay_h-10
 +The sourced input represents a life grid, each pixel represents a cell
 +which can be in one of two possible states, alive or dead. Every cell
 +interacts with its eight neighbours, which are the cells that are
 +horizontally, vertically, or diagonally adjacent.
  
 -# insert a transparent PNG logo in the bottom left corner of the input
 -avconv -i input -i logo -filter_complex 'overlay=x=10:y=main_h-overlay_h-10' output
 +At each interaction the grid evolves according to the adopted rule,
 +which specifies the number of neighbor alive cells which will make a
 +cell stay alive or born. The @option{rule} option allows to specify
 +the rule to adopt.
  
 -# insert 2 different transparent PNG logos (second logo on bottom
 -# right corner):
 -avconv -i input -i logo1 -i logo2 -filter_complex
 -'overlay=x=10:y=H-h-10,overlay=x=W-w-10:y=H-h-10' output
 +This source accepts a list of options in the form of
 +@var{key}=@var{value} pairs separated by ":". A description of the
 +accepted options follows.
  
 -# add a transparent color layer on top of the main video,
 -# WxH specifies the size of the main input to the overlay filter
 -color=red@.3:WxH [over]; [in][over] overlay [out]
 -@end example
 +@table @option
 +@item filename, f
 +Set the file from which to read the initial grid state. In the file,
 +each non-whitespace character is considered an alive cell, and newline
 +is used to delimit the end of each row.
  
 -You can chain together more overlays but the efficiency of such
 -approach is yet to be tested.
 +If this option is not specified, the initial grid is generated
 +randomly.
  
 -@section pad
 +@item rate, r
 +Set the video rate, that is the number of frames generated per second.
 +Default is 25.
 +
 +@item random_fill_ratio, ratio
 +Set the random fill ratio for the initial random grid. It is a
 +floating point number value ranging from 0 to 1, defaults to 1/PHI.
 +It is ignored when a file is specified.
 +
 +@item random_seed, seed
 +Set the seed for filling the initial random grid, must be an integer
 +included between 0 and UINT32_MAX. If not specified, or if explicitly
 +set to -1, the filter will try to use a good random seed on a best
 +effort basis.
 +
 +@item rule
 +Set the life rule.
 +
 +A rule can be specified with a code of the kind "S@var{NS}/B@var{NB}",
 +where @var{NS} and @var{NB} are sequences of numbers in the range 0-8,
 +@var{NS} specifies the number of alive neighbor cells which make a
 +live cell stay alive, and @var{NB} the number of alive neighbor cells
 +which make a dead cell to become alive (i.e. to "born").
 +"s" and "b" can be used in place of "S" and "B", respectively.
 +
 +Alternatively a rule can be specified by an 18-bits integer. The 9
 +high order bits are used to encode the next cell state if it is alive
 +for each number of neighbor alive cells, the low order bits specify
 +the rule for "borning" new cells. Higher order bits encode for an
 +higher number of neighbor cells.
 +For example the number 6153 = @code{(12<<9)+9} specifies a stay alive
 +rule of 12 and a born rule of 9, which corresponds to "S23/B03".
 +
 +Default value is "S23/B3", which is the original Conway's game of life
 +rule, and will keep a cell alive if it has 2 or 3 neighbor alive
 +cells, and will born a new cell if there are three alive cells around
 +a dead cell.
  
 -Add paddings to the input image, and places the original input at the
 -given coordinates @var{x}, @var{y}.
 +@item size, s
 +Set the size of the output video.
  
 -This filter accepts the following parameters:
 +If @option{filename} is specified, the size is set by default to the
 +same size of the input file. If @option{size} is set, it must contain
 +the size specified in the input file, and the initial grid defined in
 +that file is centered in the larger resulting area.
  
 -@table @option
 -@item width, height
 +If a filename is not specified, the size value defaults to "320x240"
 +(used for a randomly generated initial grid).
  
 -Specify the size of the output image with the paddings added. If the
 -value for @var{width} or @var{height} is 0, the corresponding input size
 -is used for the output.
 +@item stitch
 +If set to 1, stitch the left and right grid edges together, and the
 +top and bottom edges also. Defaults to 1.
  
 -The @var{width} expression can reference the value set by the
 -@var{height} expression, and vice versa.
 +@item mold
 +Set cell mold speed. If set, a dead cell will go from @option{death_color} to
 +@option{mold_color} with a step of @option{mold}. @option{mold} can have a
 +value from 0 to 255.
  
 -The default value of @var{width} and @var{height} is 0.
 +@item life_color
 +Set the color of living (or new born) cells.
  
 -@item x, y
 +@item death_color
 +Set the color of dead cells. If @option{mold} is set, this is the first color
 +used to represent a dead cell.
  
 -Specify the offsets where to place the input image in the padded area
 -with respect to the top/left border of the output image.
 +@item mold_color
 +Set mold color, for definitely dead and moldy cells.
 +@end table
  
 -The @var{x} expression can reference the value set by the @var{y}
 -expression, and vice versa.
 +@subsection Examples
  
 -The default value of @var{x} and @var{y} is 0.
 +@itemize
 +@item
 +Read a grid from @file{pattern}, and center it on a grid of size
 +300x300 pixels:
 +@example
 +life=f=pattern:s=300x300
 +@end example
  
 -@item color
 +@item
 +Generate a random grid of size 200x200, with a fill ratio of 2/3:
 +@example
 +life=ratio=2/3:s=200x200
 +@end example
  
 -Specify the color of the padded area, it can be the name of a color
 -(case insensitive match) or a 0xRRGGBB[AA] sequence.
 +@item
 +Specify a custom rule for evolving a randomly generated grid:
 +@example
 +life=rule=S14/B34
 +@end example
  
 -The default value of @var{color} is "black".
 +@item
 +Full example with slow death effect (mold) using @command{ffplay}:
 +@example
 +ffplay -f lavfi life=s=300x200:mold=10:r=60:ratio=0.1:death_color=#C83232:life_color=#00ff00,scale=1200:800:flags=16
 +@end example
 +@end itemize
  
 -@end table
 +@section color, nullsrc, rgbtestsrc, smptebars, testsrc
  
 -The parameters @var{width}, @var{height}, @var{x}, and @var{y} are
 -expressions containing the following constants:
 +The @code{color} source provides an uniformly colored input.
  
 -@table @option
 -@item E, PI, PHI
 -the corresponding mathematical approximated values for e
 -(euler number), pi (greek PI), phi (golden ratio)
 +The @code{nullsrc} source returns unprocessed video frames. It is
 +mainly useful to be employed in analysis / debugging tools, or as the
 +source for filters which ignore the input data.
  
 -@item in_w, in_h
 -the input video width and height
 +The @code{rgbtestsrc} source generates an RGB test pattern useful for
 +detecting RGB vs BGR issues. You should see a red, green and blue
 +stripe from top to bottom.
  
 -@item iw, ih
 -same as @var{in_w} and @var{in_h}
 +The @code{smptebars} source generates a color bars pattern, based on
 +the SMPTE Engineering Guideline EG 1-1990.
  
 -@item out_w, out_h
 -the output width and height, that is the size of the padded area as
 -specified by the @var{width} and @var{height} expressions
 +The @code{testsrc} source generates a test video pattern, showing a
 +color pattern, a scrolling gradient and a timestamp. This is mainly
 +intended for testing purposes.
  
 -@item ow, oh
 -same as @var{out_w} and @var{out_h}
 +These sources accept an optional sequence of @var{key}=@var{value} pairs,
 +separated by ":". The description of the accepted options follows.
  
 -@item x, y
 -x and y offsets as specified by the @var{x} and @var{y}
 -expressions, or NAN if not yet specified
 +@table @option
  
 -@item a
 -input display aspect ratio, same as @var{iw} / @var{ih}
 +@item color, c
 +Specify the color of the source, only used in the @code{color}
 +source. It can be the name of a color (case insensitive match) or a
 +0xRRGGBB[AA] sequence, possibly followed by an alpha specifier. The
 +default value is "black".
  
 -@item hsub, vsub
 -horizontal and vertical chroma subsample values. For example for the
 -pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
 -@end table
 +@item size, s
 +Specify the size of the sourced video, it may be a string of the form
 +@var{width}x@var{height}, or the name of a size abbreviation. The
 +default value is "320x240".
  
 -Some examples follow:
 +@item rate, r
 +Specify the frame rate of the sourced video, as the number of frames
 +generated per second. It has to be a string in the format
 +@var{frame_rate_num}/@var{frame_rate_den}, an integer number, a float
 +number or a valid video frame rate abbreviation. The default value is
 +"25".
 +
 +@item sar
 +Set the sample aspect ratio of the sourced video.
  
 +@item duration, d
 +Set the video duration of the sourced video. The accepted syntax is:
  @example
 -# Add paddings with color "violet" to the input video. Output video
 -# size is 640x480, the top-left corner of the input video is placed at
 -# column 0, row 40.
 -pad=width=640:height=480:x=0:y=40:color=violet
 +[-]HH[:MM[:SS[.m...]]]
 +[-]S+[.m...]
 +@end example
 +See also the function @code{av_parse_time()}.
  
 -# pad the input to get an output with dimensions increased bt 3/2,
 -# and put the input video at the center of the padded area
 -pad="3/2*iw:3/2*ih:(ow-iw)/2:(oh-ih)/2"
 +If not specified, or the expressed duration is negative, the video is
 +supposed to be generated forever.
  
 -# pad the input to get a squared output with size equal to the maximum
 -# value between the input width and height, and put the input video at
 -# the center of the padded area
 -pad="max(iw\,ih):ow:(ow-iw)/2:(oh-ih)/2"
 +@item decimals, n
 +Set the number of decimals to show in the timestamp, only used in the
 +@code{testsrc} source.
  
 -# pad the input to get a final w/h ratio of 16:9
 -pad="ih*16/9:ih:(ow-iw)/2:(oh-ih)/2"
 +The displayed timestamp value will correspond to the original
 +timestamp value multiplied by the power of 10 of the specified
 +value. Default value is 0.
 +@end table
  
 -# double output size and put the input video in the bottom-right
 -# corner of the output padded area
 -pad="2*iw:2*ih:ow-iw:oh-ih"
 +For example the following:
 +@example
 +testsrc=duration=5.3:size=qcif:rate=10
  @end example
  
 -@section pixdesctest
 +will generate a video with a duration of 5.3 seconds, with size
 +176x144 and a frame rate of 10 frames per second.
  
 -Pixel format descriptor test filter, mainly useful for internal
 -testing. The output video should be equal to the input video.
 +The following graph description will generate a red source
 +with an opacity of 0.2, with size "qcif" and a frame rate of 10
 +frames per second.
 +@example
 +color=c=red@@0.2:s=qcif:r=10
 +@end example
  
 -For example:
 +If the input content is to be ignored, @code{nullsrc} can be used. The
 +following command generates noise in the luminance plane by employing
 +the @code{geq} filter:
  @example
 -format=monow, pixdesctest
 +nullsrc=s=256x256, geq=random(1)*255:128:128
  @end example
  
 -can be used to test the monowhite pixel format descriptor definition.
 +@c man end VIDEO SOURCES
  
 -@section scale
 +@chapter Video Sinks
 +@c man begin VIDEO SINKS
 +
 +Below is a description of the currently available video sinks.
  
 -Scale the input video and/or convert the image format.
 +@section buffersink
  
 -This filter accepts the following options:
 +Buffer video frames, and make them available to the end of the filter
 +graph.
  
 -@table @option
 +This sink is mainly intended for a programmatic use, in particular
 +through the interface defined in @file{libavfilter/buffersink.h}.
  
 -@item w
 -Output video width.
 +It does not require a string parameter in input, but you need to
 +specify a pointer to a list of supported pixel formats terminated by
 +-1 in the opaque parameter provided to @code{avfilter_init_filter}
 +when initializing this sink.
  
 -@item h
 -Output video height.
 +@section nullsink
 +
 +Null video sink, do absolutely nothing with the input video. It is
 +mainly useful as a template and to be employed in analysis / debugging
 +tools.
 +
 +@c man end VIDEO SINKS
  
 -@end table
 +@chapter Multimedia Filters
 +@c man begin MULTIMEDIA FILTERS
  
 -The parameters @var{w} and @var{h} are expressions containing
 -the following constants:
 +Below is a description of the currently available multimedia filters.
  
 -@table @option
 -@item E, PI, PHI
 -the corresponding mathematical approximated values for e
 -(euler number), pi (greek PI), phi (golden ratio)
 +@section aperms, perms
  
 -@item in_w, in_h
 -the input width and height
 +Set read/write permissions for the output frames.
  
 -@item iw, ih
 -same as @var{in_w} and @var{in_h}
 +These filters are mainly aimed at developers to test direct path in the
 +following filter in the filtergraph.
  
 -@item out_w, out_h
 -the output (cropped) width and height
 +The filters accept parameters as a list of @var{key}=@var{value} pairs,
 +separated by ":". If the key of the first options is omitted, the argument is
 +assumed to be the @var{mode}.
  
 -@item ow, oh
 -same as @var{out_w} and @var{out_h}
 +A description of the accepted parameters follows.
  
 -@item dar, a
 -input display aspect ratio, same as @var{iw} / @var{ih}
 +@table @option
 +@item mode
 +Select the permissions mode.
  
 -@item sar
 -input sample aspect ratio
 +It accepts the following values:
 +@table @samp
 +@item none
 +Do nothing. This is the default.
 +@item ro
 +Set all the output frames read-only.
 +@item rw
 +Set all the output frames directly writable.
 +@item toggle
 +Make the frame read-only if writable, and writable if read-only.
 +@item random
 +Set each output frame read-only or writable randomly.
 +@end table
  
 -@item hsub, vsub
 -horizontal and vertical chroma subsample values. For example for the
 -pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
 +@item seed
 +Set the seed for the @var{random} mode, must be an integer included between
 +@code{0} and @code{UINT32_MAX}. If not specified, or if explicitly set to
 +@code{-1}, the filter will try to use a good random seed on a best effort
 +basis.
  @end table
  
 -If the input image format is different from the format requested by
 -the next filter, the scale filter will convert the input to the
 -requested format.
 +Note: in case of auto-inserted filter between the permission filter and the
 +following one, the permission might not be received as expected in that
 +following filter. Inserting a @ref{format} or @ref{aformat} filter before the
 +perms/aperms filter can avoid this problem.
  
 -If the value for @var{w} or @var{h} is 0, the respective input
 -size is used for the output.
 +@section aphaser
 +Add a phasing effect to the input audio.
  
 -If the value for @var{w} or @var{h} is -1, the scale filter will use, for the
 -respective output size, a value that maintains the aspect ratio of the input
 -image.
 +A phaser filter creates series of peaks and troughs in the frequency spectrum.
 +The position of the peaks and troughs are modulated so that they vary over time, creating a sweeping effect.
  
 -The default value of @var{w} and @var{h} is 0.
 +The filter accepts parameters as a list of @var{key}=@var{value}
 +pairs, separated by ":".
  
 -Some examples follow:
 -@example
 -# scale the input video to a size of 200x100.
 -scale=w=200:h=100
 +A description of the accepted parameters follows.
  
 -# scale the input to 2x
 -scale=w=2*iw:h=2*ih
 -# the above is the same as
 -scale=2*in_w:2*in_h
 +@table @option
 +@item in_gain
 +Set input gain. Default is 0.4.
  
 -# scale the input to half size
 -scale=w=iw/2:h=ih/2
 +@item out_gain
 +Set output gain. Default is 0.74
  
 -# increase the width, and set the height to the same size
 -scale=3/2*iw:ow
 +@item delay
 +Set delay in milliseconds. Default is 3.0.
  
 -# seek for Greek harmony
 -scale=iw:1/PHI*iw
 -scale=ih*PHI:ih
 +@item decay
 +Set decay. Default is 0.4.
  
 -# increase the height, and set the width to 3/2 of the height
 -scale=w=3/2*oh:h=3/5*ih
 +@item speed
 +Set modulation speed in Hz. Default is 0.5.
  
 -# increase the size, but make the size a multiple of the chroma
 -scale="trunc(3/2*iw/hsub)*hsub:trunc(3/2*ih/vsub)*vsub"
 +@item type
 +Set modulation type. Default is triangular.
  
 -# increase the width to a maximum of 500 pixels, keep the same input aspect ratio
 -scale=w='min(500\, iw*3/2):h=-1'
 -@end example
 +It accepts the following values:
 +@table @samp
 +@item triangular, t
 +@item sinusoidal, s
 +@end table
 +@end table
  
 -@section select
 +@section aselect, select
  Select frames to pass in output.
  
- These filters accept a single option @option{expr} or @option{e}
- specifying the select expression, which can be specified either by
- specyfing @code{expr=VALUE} or specifying the expression
- alone.
- The select expression is evaluated for each input frame. If the
- evaluation result is a non-zero value, the frame is selected and
- passed to the output, otherwise it is discarded.
+ This filter accepts the following options:
+ @table @option
+ @item expr
+ An expression, which is evaluated for each input frame. If the expression is
+ evaluated to a non-zero value, the frame is selected and passed to the output,
+ otherwise it is discarded.
+ @end table
  
  The expression can contain the following constants:
  
@@@ -655,49 -479,8 +655,50 @@@ int avfilter_init_filter(AVFilterContex
      AVDictionary *options = NULL;
      AVDictionaryEntry *e;
      int ret=0;
 +    int anton_options =
 +        !strcmp(filter->filter->name,  "aformat") ||
 +        !strcmp(filter->filter->name,  "blackframe") ||
 +        !strcmp(filter->filter->name,  "boxblur"   ) ||
 +        !strcmp(filter->filter->name,  "crop"      ) ||
 +        !strcmp(filter->filter->name,  "cropdetect") ||
 +        !strcmp(filter->filter->name,  "delogo"    ) ||
 +        !strcmp(filter->filter->name,  "drawbox"   ) ||
 +        !strcmp(filter->filter->name,  "drawtext"  ) ||
 +        !strcmp(filter->filter->name,  "fade"      ) ||
 +        !strcmp(filter->filter->name,  "fieldorder") ||
 +        !strcmp(filter->filter->name,  "fps"       ) ||
 +        !strcmp(filter->filter->name,  "frei0r"    ) ||
 +        !strcmp(filter->filter->name,  "frei0r_src") ||
 +        !strcmp(filter->filter->name, "gradfun"    ) ||
 +        !strcmp(filter->filter->name, "hqdn3d"     ) ||
 +        !strcmp(filter->filter->name, "ocv"        ) ||
 +        !strcmp(filter->filter->name, "lut"        ) ||
 +        !strcmp(filter->filter->name, "lutyuv"     ) ||
 +        !strcmp(filter->filter->name, "lutrgb"     ) ||
 +        !strcmp(filter->filter->name, "negate"     ) ||
 +        !strcmp(filter->filter->name, "overlay"    ) ||
 +        !strcmp(filter->filter->name, "pad"        ) ||
 +        !strcmp(filter->filter->name,   "format") ||
 +        !strcmp(filter->filter->name, "noformat") ||
 +        !strcmp(filter->filter->name, "resample") ||
 +//         !strcmp(filter->filter->name, "scale"      ) ||
++        !strcmp(filter->filter->name, "select") ||
 +        0
 +        ;
 +
 +    if (filter->filter->shorthand) {
 +        av_assert0(filter->priv);
 +        av_assert0(filter->filter->priv_class);
 +        *(const AVClass **)filter->priv = filter->filter->priv_class;
 +        av_opt_set_defaults(filter->priv);
 +        ret = av_opt_set_from_string(filter->priv, args,
 +                                     filter->filter->shorthand, "=", ":");
 +        if (ret < 0)
 +            return ret;
 +        args = NULL;
 +    }
  
 -    if (args && *args && filter->filter->priv_class) {
 +    if (anton_options && args && *args && filter->filter->priv_class) {
  #if FF_API_OLD_FILTER_OPTS
          if (!strcmp(filter->filter->name, "scale") &&
              strchr(args, ':') < strchr(args, '=')) {
index 351b7f8,0000000..e2c4ef7
mode 100644,000000..100644
--- /dev/null
@@@ -1,507 -1,0 +1,513 @@@
-     AVExpr *expr;
 +/*
 + * Copyright (c) 2011 Stefano Sabatini
 + *
 + * This file is part of FFmpeg.
 + *
 + * FFmpeg is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + *
 + * FFmpeg is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with FFmpeg; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 + */
 +
 +/**
 + * @file
 + * filter for selecting which frame passes in the filterchain
 + */
 +
 +#include "libavutil/eval.h"
 +#include "libavutil/fifo.h"
 +#include "libavutil/internal.h"
 +#include "libavutil/opt.h"
 +#include "avfilter.h"
 +#include "audio.h"
 +#include "formats.h"
 +#include "internal.h"
 +#include "video.h"
 +
 +#if CONFIG_AVCODEC
 +#include "libavcodec/dsputil.h"
 +#endif
 +
 +static const char *const var_names[] = {
 +    "TB",                ///< timebase
 +
 +    "pts",               ///< original pts in the file of the frame
 +    "start_pts",         ///< first PTS in the stream, expressed in TB units
 +    "prev_pts",          ///< previous frame PTS
 +    "prev_selected_pts", ///< previous selected frame PTS
 +
 +    "t",                 ///< first PTS in seconds
 +    "start_t",           ///< first PTS in the stream, expressed in seconds
 +    "prev_t",            ///< previous frame time
 +    "prev_selected_t",   ///< previously selected time
 +
 +    "pict_type",         ///< the type of picture in the movie
 +    "I",
 +    "P",
 +    "B",
 +    "S",
 +    "SI",
 +    "SP",
 +    "BI",
 +
 +    "interlace_type",    ///< the frame interlace type
 +    "PROGRESSIVE",
 +    "TOPFIRST",
 +    "BOTTOMFIRST",
 +
 +    "consumed_samples_n",///< number of samples consumed by the filter (only audio)
 +    "samples_n",         ///< number of samples in the current frame (only audio)
 +    "sample_rate",       ///< sample rate (only audio)
 +
 +    "n",                 ///< frame number (starting from zero)
 +    "selected_n",        ///< selected frame number (starting from zero)
 +    "prev_selected_n",   ///< number of the last selected frame
 +
 +    "key",               ///< tell if the frame is a key frame
 +    "pos",               ///< original position in the file of the frame
 +
 +    "scene",
 +
 +    NULL
 +};
 +
 +enum var_name {
 +    VAR_TB,
 +
 +    VAR_PTS,
 +    VAR_START_PTS,
 +    VAR_PREV_PTS,
 +    VAR_PREV_SELECTED_PTS,
 +
 +    VAR_T,
 +    VAR_START_T,
 +    VAR_PREV_T,
 +    VAR_PREV_SELECTED_T,
 +
 +    VAR_PICT_TYPE,
 +    VAR_PICT_TYPE_I,
 +    VAR_PICT_TYPE_P,
 +    VAR_PICT_TYPE_B,
 +    VAR_PICT_TYPE_S,
 +    VAR_PICT_TYPE_SI,
 +    VAR_PICT_TYPE_SP,
 +    VAR_PICT_TYPE_BI,
 +
 +    VAR_INTERLACE_TYPE,
 +    VAR_INTERLACE_TYPE_P,
 +    VAR_INTERLACE_TYPE_T,
 +    VAR_INTERLACE_TYPE_B,
 +
 +    VAR_CONSUMED_SAMPLES_N,
 +    VAR_SAMPLES_N,
 +    VAR_SAMPLE_RATE,
 +
 +    VAR_N,
 +    VAR_SELECTED_N,
 +    VAR_PREV_SELECTED_N,
 +
 +    VAR_KEY,
 +    VAR_POS,
 +
 +    VAR_SCENE,
 +
 +    VAR_VARS_NB
 +};
 +
 +typedef struct {
 +    const AVClass *class;
- #define OFFSET(x) offsetof(SelectContext, x)
- #define FLAGS AV_OPT_FLAG_FILTERING_PARAM
- static const AVOption options[] = {
-     { "expr", "set selection expression", OFFSET(expr_str), AV_OPT_TYPE_STRING, {.str = "1"}, 0, 0, FLAGS },
-     { "e",    "set selection expression", OFFSET(expr_str), AV_OPT_TYPE_STRING, {.str = "1"}, 0, 0, FLAGS },
-     {NULL},
- };
 +    char *expr_str;
++    AVExpr *expr;
 +    double var_values[VAR_VARS_NB];
 +    int do_scene_detect;            ///< 1 if the expression requires scene detection variables, 0 otherwise
 +#if CONFIG_AVCODEC
 +    AVCodecContext *avctx;          ///< codec context required for the DSPContext (scene detect only)
 +    DSPContext c;                   ///< context providing optimized SAD methods   (scene detect only)
 +    double prev_mafd;               ///< previous MAFD                             (scene detect only)
 +#endif
 +    AVFrame *prev_picref; ///< previous frame                            (scene detect only)
 +    double select;
 +} SelectContext;
 +
-         av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n", select->expr_str);
 +
 +static av_cold int init(AVFilterContext *ctx, const char *args, const AVClass *class)
 +{
 +    SelectContext *select = ctx->priv;
 +    int ret;
 +
 +    if ((ret = av_expr_parse(&select->expr, select->expr_str,
 +                             var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
- #define aselect_options options
++        av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n",
++               select->expr_str);
 +        return ret;
 +    }
 +    select->do_scene_detect = !!strstr(select->expr_str, "scene");
 +
 +    return 0;
 +}
 +
 +#define INTERLACE_TYPE_P 0
 +#define INTERLACE_TYPE_T 1
 +#define INTERLACE_TYPE_B 2
 +
 +static int config_input(AVFilterLink *inlink)
 +{
 +    SelectContext *select = inlink->dst->priv;
 +
 +    select->var_values[VAR_N]          = 0.0;
 +    select->var_values[VAR_SELECTED_N] = 0.0;
 +
 +    select->var_values[VAR_TB] = av_q2d(inlink->time_base);
 +
 +    select->var_values[VAR_PREV_PTS]          = NAN;
 +    select->var_values[VAR_PREV_SELECTED_PTS] = NAN;
 +    select->var_values[VAR_PREV_SELECTED_T]   = NAN;
 +    select->var_values[VAR_PREV_T]            = NAN;
 +    select->var_values[VAR_START_PTS]         = NAN;
 +    select->var_values[VAR_START_T]           = NAN;
 +
 +    select->var_values[VAR_PICT_TYPE_I]  = AV_PICTURE_TYPE_I;
 +    select->var_values[VAR_PICT_TYPE_P]  = AV_PICTURE_TYPE_P;
 +    select->var_values[VAR_PICT_TYPE_B]  = AV_PICTURE_TYPE_B;
 +    select->var_values[VAR_PICT_TYPE_SI] = AV_PICTURE_TYPE_SI;
 +    select->var_values[VAR_PICT_TYPE_SP] = AV_PICTURE_TYPE_SP;
 +
 +    select->var_values[VAR_INTERLACE_TYPE_P] = INTERLACE_TYPE_P;
 +    select->var_values[VAR_INTERLACE_TYPE_T] = INTERLACE_TYPE_T;
 +    select->var_values[VAR_INTERLACE_TYPE_B] = INTERLACE_TYPE_B;
 +
 +    select->var_values[VAR_PICT_TYPE]         = NAN;
 +    select->var_values[VAR_INTERLACE_TYPE]    = NAN;
 +    select->var_values[VAR_SCENE]             = NAN;
 +    select->var_values[VAR_CONSUMED_SAMPLES_N] = NAN;
 +    select->var_values[VAR_SAMPLES_N]          = NAN;
 +
 +    select->var_values[VAR_SAMPLE_RATE] =
 +        inlink->type == AVMEDIA_TYPE_AUDIO ? inlink->sample_rate : NAN;
 +
 +#if CONFIG_AVCODEC
 +    if (select->do_scene_detect) {
 +        select->avctx = avcodec_alloc_context3(NULL);
 +        if (!select->avctx)
 +            return AVERROR(ENOMEM);
 +        dsputil_init(&select->c, select->avctx);
 +    }
 +#endif
 +    return 0;
 +}
 +
 +#if CONFIG_AVCODEC
 +static double get_scene_score(AVFilterContext *ctx, AVFrame *frame)
 +{
 +    double ret = 0;
 +    SelectContext *select = ctx->priv;
 +    AVFrame *prev_picref = select->prev_picref;
 +
 +    if (prev_picref &&
 +        frame->height    == prev_picref->height &&
 +        frame->width    == prev_picref->width &&
 +        frame->linesize[0] == prev_picref->linesize[0]) {
 +        int x, y, nb_sad = 0;
 +        int64_t sad = 0;
 +        double mafd, diff;
 +        uint8_t *p1 =      frame->data[0];
 +        uint8_t *p2 = prev_picref->data[0];
 +        const int linesize = frame->linesize[0];
 +
 +        for (y = 0; y < frame->height - 8; y += 8) {
 +            for (x = 0; x < frame->width*3 - 8; x += 8) {
 +                sad += select->c.sad[1](select, p1 + x, p2 + x,
 +                                        linesize, 8);
 +                nb_sad += 8 * 8;
 +            }
 +            p1 += 8 * linesize;
 +            p2 += 8 * linesize;
 +        }
 +        emms_c();
 +        mafd = nb_sad ? sad / nb_sad : 0;
 +        diff = fabs(mafd - select->prev_mafd);
 +        ret  = av_clipf(FFMIN(mafd, diff) / 100., 0, 1);
 +        select->prev_mafd = mafd;
 +        av_frame_free(&prev_picref);
 +    }
 +    select->prev_picref = av_frame_clone(frame);
 +    return ret;
 +}
 +#endif
 +
 +#define D2TS(d)  (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d))
 +#define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
 +
 +static int select_frame(AVFilterContext *ctx, AVFrame *frame)
 +{
 +    SelectContext *select = ctx->priv;
 +    AVFilterLink *inlink = ctx->inputs[0];
 +    double res;
 +
 +    if (isnan(select->var_values[VAR_START_PTS]))
 +        select->var_values[VAR_START_PTS] = TS2D(frame->pts);
 +    if (isnan(select->var_values[VAR_START_T]))
 +        select->var_values[VAR_START_T] = TS2D(frame->pts) * av_q2d(inlink->time_base);
 +
 +    select->var_values[VAR_PTS] = TS2D(frame->pts);
 +    select->var_values[VAR_T  ] = TS2D(frame->pts) * av_q2d(inlink->time_base);
 +    select->var_values[VAR_POS] = av_frame_get_pkt_pos(frame) == -1 ? NAN : av_frame_get_pkt_pos(frame);
 +
 +    switch (inlink->type) {
 +    case AVMEDIA_TYPE_AUDIO:
 +        select->var_values[VAR_SAMPLES_N] = frame->nb_samples;
 +        break;
 +
 +    case AVMEDIA_TYPE_VIDEO:
 +        select->var_values[VAR_INTERLACE_TYPE] =
 +            !frame->interlaced_frame ? INTERLACE_TYPE_P :
 +        frame->top_field_first ? INTERLACE_TYPE_T : INTERLACE_TYPE_B;
 +        select->var_values[VAR_PICT_TYPE] = frame->pict_type;
 +#if CONFIG_AVCODEC
 +        if (select->do_scene_detect) {
 +            char buf[32];
 +            select->var_values[VAR_SCENE] = get_scene_score(ctx, frame);
 +            // TODO: document metadata
 +            snprintf(buf, sizeof(buf), "%f", select->var_values[VAR_SCENE]);
 +            av_dict_set(&frame->metadata, "lavfi.scene_score", buf, 0);
 +        }
 +#endif
 +        break;
 +    }
 +
 +    res = av_expr_eval(select->expr, select->var_values, NULL);
 +    av_log(inlink->dst, AV_LOG_DEBUG,
 +           "n:%f pts:%f t:%f key:%d",
 +           select->var_values[VAR_N],
 +           select->var_values[VAR_PTS],
 +           select->var_values[VAR_T],
 +           (int)select->var_values[VAR_KEY]);
 +
 +    switch (inlink->type) {
 +    case AVMEDIA_TYPE_VIDEO:
 +        av_log(inlink->dst, AV_LOG_DEBUG, " interlace_type:%c pict_type:%c scene:%f",
 +               select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_P ? 'P' :
 +               select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_T ? 'T' :
 +               select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_B ? 'B' : '?',
 +               av_get_picture_type_char(select->var_values[VAR_PICT_TYPE]),
 +               select->var_values[VAR_SCENE]);
 +        break;
 +    case AVMEDIA_TYPE_AUDIO:
 +        av_log(inlink->dst, AV_LOG_DEBUG, " samples_n:%d consumed_samples_n:%d",
 +               (int)select->var_values[VAR_SAMPLES_N],
 +               (int)select->var_values[VAR_CONSUMED_SAMPLES_N]);
 +        break;
 +    }
 +
 +    av_log(inlink->dst, AV_LOG_DEBUG, " -> select:%f\n", res);
 +
 +    if (res) {
 +        select->var_values[VAR_PREV_SELECTED_N]   = select->var_values[VAR_N];
 +        select->var_values[VAR_PREV_SELECTED_PTS] = select->var_values[VAR_PTS];
 +        select->var_values[VAR_PREV_SELECTED_T]   = select->var_values[VAR_T];
 +        select->var_values[VAR_SELECTED_N] += 1.0;
 +        if (inlink->type == AVMEDIA_TYPE_AUDIO)
 +            select->var_values[VAR_CONSUMED_SAMPLES_N] += frame->nb_samples;
 +    }
 +
 +    select->var_values[VAR_N] += 1.0;
 +    select->var_values[VAR_PREV_PTS] = select->var_values[VAR_PTS];
 +    select->var_values[VAR_PREV_T]   = select->var_values[VAR_T];
 +
 +    return res;
 +}
 +
 +static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 +{
 +    SelectContext *select = inlink->dst->priv;
 +
 +    select->select = select_frame(inlink->dst, frame);
 +    if (select->select)
 +        return ff_filter_frame(inlink->dst->outputs[0], frame);
 +
 +    av_frame_free(&frame);
 +    return 0;
 +}
 +
 +static int request_frame(AVFilterLink *outlink)
 +{
 +    AVFilterContext *ctx = outlink->src;
 +    SelectContext *select = ctx->priv;
 +    AVFilterLink *inlink = outlink->src->inputs[0];
 +    select->select = 0;
 +
 +    do {
 +        int ret = ff_request_frame(inlink);
 +        if (ret < 0)
 +            return ret;
 +    } while (!select->select);
 +
 +    return 0;
 +}
 +
 +static av_cold void uninit(AVFilterContext *ctx)
 +{
 +    SelectContext *select = ctx->priv;
 +
 +    av_expr_free(select->expr);
 +    select->expr = NULL;
 +
 +#if CONFIG_AVCODEC
 +    if (select->do_scene_detect) {
 +        av_frame_free(&select->prev_picref);
 +        if (select->avctx) {
 +            avcodec_close(select->avctx);
 +            av_freep(&select->avctx);
 +        }
 +    }
 +#endif
 +}
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    SelectContext *select = ctx->priv;
 +
 +    if (!select->do_scene_detect) {
 +        return ff_default_query_formats(ctx);
 +    } else {
 +        static const enum AVPixelFormat pix_fmts[] = {
 +            AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
 +            AV_PIX_FMT_NONE
 +        };
 +        ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
 +    }
 +    return 0;
 +}
 +
 +static const char *const shorthand[] = { "expr", NULL };
 +
 +#if CONFIG_ASELECT_FILTER
 +
- #define select_options options
++#define OFFSET(x) offsetof(SelectContext, x)
++#define AFLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_AUDIO_PARAM
++static const AVOption aselect_options[] = {
++    { "expr", "An expression to use for selecting frames", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = AFLAGS },
++    { "e",    "An expression to use for selecting frames", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = AFLAGS },
++    { NULL },
++};
 +AVFILTER_DEFINE_CLASS(aselect);
 +
 +static av_cold int aselect_init(AVFilterContext *ctx, const char *args)
 +{
 +    SelectContext *select = ctx->priv;
 +    int ret;
 +
 +    if ((ret = init(ctx, args, &aselect_class)) < 0)
 +        return ret;
 +
 +    if (select->do_scene_detect) {
 +        av_log(ctx, AV_LOG_ERROR, "Scene detection is ignored in aselect filter\n");
 +        return AVERROR(EINVAL);
 +    }
 +
 +    return 0;
 +}
 +
 +static const AVFilterPad avfilter_af_aselect_inputs[] = {
 +    {
 +        .name             = "default",
 +        .type             = AVMEDIA_TYPE_AUDIO,
 +        .get_audio_buffer = ff_null_get_audio_buffer,
 +        .config_props     = config_input,
 +        .filter_frame     = filter_frame,
 +    },
 +    { NULL }
 +};
 +
 +static const AVFilterPad avfilter_af_aselect_outputs[] = {
 +    {
 +        .name = "default",
 +        .type = AVMEDIA_TYPE_AUDIO,
 +    },
 +    { NULL }
 +};
 +
 +AVFilter avfilter_af_aselect = {
 +    .name      = "aselect",
 +    .description = NULL_IF_CONFIG_SMALL("Select audio frames to pass in output."),
 +    .init      = aselect_init,
 +    .uninit    = uninit,
 +    .priv_size = sizeof(SelectContext),
 +    .inputs    = avfilter_af_aselect_inputs,
 +    .outputs   = avfilter_af_aselect_outputs,
 +    .priv_class = &aselect_class,
 +    .shorthand  = shorthand,
 +};
 +#endif /* CONFIG_ASELECT_FILTER */
 +
 +#if CONFIG_SELECT_FILTER
 +
-     .priv_class = &select_class,
-     .shorthand  = shorthand,
++#define OFFSET(x) offsetof(SelectContext, x)
++#define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM
++static const AVOption select_options[] = {
++    { "expr", "An expression to use for selecting frames", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = FLAGS },
++    { "e",    "An expression to use for selecting frames", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = FLAGS },
++    { NULL },
++};
++
 +AVFILTER_DEFINE_CLASS(select);
 +
 +static av_cold int select_init(AVFilterContext *ctx, const char *args)
 +{
 +    SelectContext *select = ctx->priv;
 +    int ret;
 +
 +    if ((ret = init(ctx, args, &select_class)) < 0)
 +        return ret;
 +
 +    if (select->do_scene_detect && !CONFIG_AVCODEC) {
 +        av_log(ctx, AV_LOG_ERROR, "Scene detection is not available without libavcodec.\n");
 +        return AVERROR(EINVAL);
 +    }
 +
 +    return 0;
 +}
 +
 +static const AVFilterPad avfilter_vf_select_inputs[] = {
 +    {
 +        .name             = "default",
 +        .type             = AVMEDIA_TYPE_VIDEO,
 +        .get_video_buffer = ff_null_get_video_buffer,
 +        .config_props     = config_input,
 +        .filter_frame     = filter_frame,
 +    },
 +    { NULL }
 +};
 +
 +static const AVFilterPad avfilter_vf_select_outputs[] = {
 +    {
 +        .name          = "default",
 +        .type          = AVMEDIA_TYPE_VIDEO,
 +        .request_frame = request_frame,
 +    },
 +    { NULL }
 +};
 +
 +AVFilter avfilter_vf_select = {
 +    .name      = "select",
 +    .description = NULL_IF_CONFIG_SMALL("Select video frames to pass in output."),
 +    .init      = select_init,
 +    .uninit    = uninit,
 +    .query_formats = query_formats,
 +
 +    .priv_size = sizeof(SelectContext),
++    .priv_class = &select_class,
 +
 +    .inputs    = avfilter_vf_select_inputs,
 +    .outputs   = avfilter_vf_select_outputs,
 +};
 +#endif /* CONFIG_SELECT_FILTER */