[FFmpeg-devel] [PATCH] lavfi/deshake: support named options.

Stefano Sabatini stefasab at gmail.com
Tue Mar 5 20:34:46 CET 2013


On date Tuesday 2013-03-05 20:21:06 +0100, Clément Bœsch encoded:
> TODO: bump micro
> ---

> The blocksize option is strangely handled; I kept the default behaviour, even
> though it doesn't look correct.
> ---
>  doc/filters.texi         | 26 +++++++++------
>  libavfilter/vf_deshake.c | 84 +++++++++++++++++++++++++++++-------------------
>  2 files changed, 68 insertions(+), 42 deletions(-)
> 
> diff --git a/doc/filters.texi b/doc/filters.texi
> index 5cfe531..6924241 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -2288,8 +2288,10 @@ Attempt to fix small changes in horizontal and/or vertical shift. This
>  filter helps remove camera shake from hand-holding a camera, bumping a
>  tripod, moving on a vehicle, etc.
>  
> -The filter accepts parameters as a string of the form
> -"@var{x}:@var{y}:@var{w}:@var{h}:@var{rx}:@var{ry}:@var{edge}:@var{blocksize}:@var{contrast}:@var{search}:@var{filename}"
> +The filter accepts parameters as a list of @var{key}=@var{value}
> +pairs, separated by ":". If the key of the first options is omitted,
> +the arguments are interpreted according to the syntax
> + at var{x}:@var{y}:@var{w}:@var{h}:@var{rx}:@var{ry}:@var{edge}:@var{blocksize}:@var{contrast}:@var{search}:@var{filename}.
>  
>  A description of the accepted parameters follows.
>  
> @@ -2319,15 +2321,15 @@ range 0-64 pixels. Default 16.
>  
>  @item edge
>  Specify how to generate pixels to fill blanks at the edge of the
> -frame. An integer from 0 to 3 as follows:
> +frame.

Available values are:

>  @table @option

@table @samp is another possibility (with a possibly better rendering,
considering they are not "options" but values).

> - at item 0
> + at item blank, 0
>  Fill zeroes at blank locations
> - at item 1
> + at item original, 1
>  Original image at blank locations
> - at item 2
> + at item clamp, 2
>  Extruded edge value at blank locations
> - at item 3
> + at item mirror, 3
>  Mirrored edge at blank locations
>  @end table

Mention the default while at it.

>  
> @@ -2343,8 +2345,14 @@ the specified contrast (difference between darkest and lightest
>  pixels) will be considered. Range 1-255, default 125.
>  
>  @item search
> -Specify the search strategy 0 = exhaustive search, 1 = less exhaustive
> -search. Default - exhaustive search.
> +Specify the search strategy.

Available values are:

> + at table @option
> + at item exhaustive, 0
> +Set exhaustive search
> + at item less, 1
> +Set less exhaustive search.
> + at end table

> +Default - exhaustive search.

Default value is @samp{exhaustive}.

>  
>  @item filename
>  If set then a detailed log of the motion search is written to the
> diff --git a/libavfilter/vf_deshake.c b/libavfilter/vf_deshake.c
> index c03919c..26f92f4 100644
> --- a/libavfilter/vf_deshake.c
> +++ b/libavfilter/vf_deshake.c
> @@ -55,6 +55,7 @@
>  #include "video.h"
>  #include "libavutil/common.h"
>  #include "libavutil/mem.h"
> +#include "libavutil/opt.h"
>  #include "libavutil/pixdesc.h"
>  #include "libavcodec/dsputil.h"
>  
> @@ -86,7 +87,7 @@ typedef struct {
>  } Transform;
>  
>  typedef struct {
> -    AVClass av_class;
> +    const AVClass *class;
>      AVFilterBufferRef *ref;    ///< Previous frame
>      int rx;                    ///< Maximum horizontal shift
>      int ry;                    ///< Maximum vertical shift
> @@ -104,8 +105,35 @@ typedef struct {
>      int ch;
>      int cx;
>      int cy;
> +    char *filename;            ///< Motion search detailed log filename
>  } DeshakeContext;
>  
> +#define OFFSET(x) offsetof(DeshakeContext, x)
> +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
> +
> +static const AVOption deshake_options[] = {
> +    { "x", "set x for the rectangular search area",      OFFSET(cx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
> +    { "y", "set y for the rectangular search area",      OFFSET(cy), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
> +    { "w", "set width for the rectangular search area",  OFFSET(cw), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
> +    { "h", "set height for the rectangular search area", OFFSET(ch), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
> +    { "rx", "set x for the rectangular search area",     OFFSET(rx), AV_OPT_TYPE_INT, {.i64=16}, 0, 64, .flags = FLAGS },
> +    { "ry", "set y for the rectangular search area",     OFFSET(ry), AV_OPT_TYPE_INT, {.i64=16}, 0, 64, .flags = FLAGS },
> +    { "edge", "set edge mode", OFFSET(edge), AV_OPT_TYPE_INT, {.i64=FILL_MIRROR}, FILL_BLANK, FILL_COUNT-1, FLAGS, "edge"},
> +        { "blank",    "fill zeroes at blank locations",         0, AV_OPT_TYPE_CONST, {.i64=FILL_BLANK},    INT_MIN, INT_MAX, FLAGS, "edge" },
> +        { "original", "original image at blank locations",      0, AV_OPT_TYPE_CONST, {.i64=FILL_ORIGINAL}, INT_MIN, INT_MAX, FLAGS, "edge" },
> +        { "clamp",    "extruded edge value at blank locations", 0, AV_OPT_TYPE_CONST, {.i64=FILL_CLAMP},    INT_MIN, INT_MAX, FLAGS, "edge" },
> +        { "mirror",   "mirrored edge at blank locations",       0, AV_OPT_TYPE_CONST, {.i64=FILL_MIRROR},   INT_MIN, INT_MAX, FLAGS, "edge" },
> +    { "blocksize", "set motion search blocksize",       OFFSET(blocksize), AV_OPT_TYPE_INT, {.i64=8},   4, 128, .flags = FLAGS },
> +    { "contrast",  "set contrast threshold for blocks", OFFSET(contrast),  AV_OPT_TYPE_INT, {.i64=125}, 1, 255, .flags = FLAGS },
> +    { "search",  "set search strategy", OFFSET(search), AV_OPT_TYPE_INT, {.i64=EXHAUSTIVE}, EXHAUSTIVE, SEARCH_COUNT-1, FLAGS, "smode" },
> +        { "exhaustive", "exhaustive search",      0, AV_OPT_TYPE_CONST, {.i64=EXHAUSTIVE},       INT_MIN, INT_MAX, FLAGS, "smode" },
> +        { "less",       "less exhaustive search", 0, AV_OPT_TYPE_CONST, {.i64=SMART_EXHAUSTIVE}, INT_MIN, INT_MAX, FLAGS, "smode" },
> +    { "filename", "set motion search detailed log file name", OFFSET(filename), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
> +    { NULL }
> +};
> +
> +AVFILTER_DEFINE_CLASS(deshake);
> +
>  static int cmp(const double *a, const double *b)
>  {
>      return *a < *b ? -1 : ( *a > *b ? 1 : 0 );
> @@ -334,40 +362,28 @@ static void find_motion(DeshakeContext *deshake, uint8_t *src1, uint8_t *src2,
>  
>  static av_cold int init(AVFilterContext *ctx, const char *args)
>  {
> +    int ret;
>      DeshakeContext *deshake = ctx->priv;
> -    char filename[256] = {0};
> -
> -    deshake->rx = 16;
> -    deshake->ry = 16;
> -    deshake->edge = FILL_MIRROR;
> -    deshake->blocksize = 8;
> -    deshake->contrast = 125;
> -    deshake->search = EXHAUSTIVE;
> -    deshake->refcount = 20;
> -
> -    deshake->cw = -1;
> -    deshake->ch = -1;
> -    deshake->cx = -1;
> -    deshake->cy = -1;
> -
> -    if (args) {
> -        sscanf(args, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%255s",
> -               &deshake->cx, &deshake->cy, &deshake->cw, &deshake->ch,
> -               &deshake->rx, &deshake->ry, &deshake->edge,
> -               &deshake->blocksize, &deshake->contrast, &deshake->search, filename);
> -
> -        deshake->blocksize /= 2;
> -
> -        deshake->rx = av_clip(deshake->rx, 0, 64);
> -        deshake->ry = av_clip(deshake->ry, 0, 64);
> -        deshake->edge = av_clip(deshake->edge, FILL_BLANK, FILL_COUNT - 1);
> -        deshake->blocksize = av_clip(deshake->blocksize, 4, 128);
> -        deshake->contrast = av_clip(deshake->contrast, 1, 255);
> -        deshake->search = av_clip(deshake->search, EXHAUSTIVE, SEARCH_COUNT - 1);
> +    static const char *shorthand[] = {
> +        "x", "y", "w", "h", "rx", "ry", "edge",
> +        "blocksize", "contrast", "search", "filename",
> +        NULL
> +    };
>  
> -    }
> -    if (*filename)
> -        deshake->fp = fopen(filename, "w");
> +    deshake->refcount = 20; // XXX: add to options?
> +
> +    deshake->class = &deshake_class;
> +    av_opt_set_defaults(deshake);
> +
> +    ret = av_opt_set_from_string(deshake, args, shorthand, "=", ":");
> +    if (ret < 0)
> +        return ret;
> +
> +    deshake->blocksize /= 2;
> +    deshake->blocksize = av_clip(deshake->blocksize, 4, 128);
> +
> +    if (deshake->filename)
> +        deshake->fp = fopen(deshake->filename, "w");
>      if (deshake->fp)
>          fwrite("Ori x, Avg x, Fin x, Ori y, Avg y, Fin y, Ori angle, Avg angle, Fin angle, Ori zoom, Avg zoom, Fin zoom\n", sizeof(char), 104, deshake->fp);
>  
> @@ -424,6 +440,7 @@ static av_cold void uninit(AVFilterContext *ctx)
>      if (deshake->avctx)
>          avcodec_close(deshake->avctx);
>      av_freep(&deshake->avctx);
> +    av_opt_free(deshake);
>  }
>  
>  static int filter_frame(AVFilterLink *link, AVFilterBufferRef *in)
> @@ -565,4 +582,5 @@ AVFilter avfilter_vf_deshake = {
>      .query_formats = query_formats,
>      .inputs        = deshake_inputs,
>      .outputs       = deshake_outputs,
> +    .priv_class    = &deshake_class,
>  };

LGTM otherwise, thanks.

About the blocksize thing, a separate patch may avoid the weird /2 and
clip.
-- 
FFmpeg = Forgiving and Fascinating Mastodontic Political Extensive Geisha


More information about the ffmpeg-devel mailing list