Hi, this greatly boosts the crop filter exressivity.
Regards.
Index: ffmpeg-vfilters/ffmpeg/doc/vfilters.texi =================================================================== --- ffmpeg-vfilters.orig/ffmpeg/doc/vfilters.texi 2009-10-04 22:21:32.000000000 +0200 +++ ffmpeg-vfilters/ffmpeg/doc/vfilters.texi 2009-10-04 22:38:22.000000000 +0200 @@ -72,11 +72,53 @@ @section crop @example -./ffmpeg -i in.avi -vfilters "crop=0:0:-1:240" out.avi +./ffmpeg -i in.avi -vfilters "crop= x=0 : y=0: out_w= in_w/2" out.avi @end example -Crop the input video to x:y:width:height. -The -1 in width or height means that dimension in the input video. +Crop the input video. + +Parameters are specified as a list of non-positional key=value pairs +separated by ``:''. + +...@table @option +...@item out_w, out_h + +Specify the expressions used for computing width and height (default: +original width, height). Negative values will results in subtracting +to the input size. For example the expression ``out_w=-100'' is +equivalent to ``out_w=in_w-100''. + +The expressions can contain the ``in_w'' and ``in_h'' variables which +contain the values of the input size. + +...@item x, y + +Specify the expressions used for computing the coordinates of the crop +area to extract from the input area, with respect to the top/left +border. If the values are negative, they are subtracted to the maximum +value they can have, which are respectively ``in_w-out_w'' and +``in_h-out_h''. + +The expressions can contain the ``in_w'' and ``in_h'' variables which +contain the values of the original size, and the ``out_w'' and +``out_h'' variables which contain the values of the padded area +size. Default expressions for both x and y are ``0''. + +For example to place the cropped area exactly in the center of the +input image, use the expressions: + +...@example +crop= out_w=in_w / 2 : out_h=in_h/2 : x=(in_w-out_w)/2 : y=(in_h-out_w)/2 +...@end example + +For placing the cropped area near to the bottom right corner use the +expressions: + +...@example +crop= out_w=in_w / 2 : out_h=in_h/2 : x=in_w : y=out_h +...@end example + +...@end table @section drawbox Index: ffmpeg-vfilters/ffmpeg/libavfilter/vf_crop.c =================================================================== --- ffmpeg-vfilters.orig/ffmpeg/libavfilter/vf_crop.c 2009-10-04 22:21:32.000000000 +0200 +++ ffmpeg-vfilters/ffmpeg/libavfilter/vf_crop.c 2009-10-04 22:24:36.000000000 +0200 @@ -22,9 +22,40 @@ #include <stdio.h> #include "avfilter.h" +#include "parseutils.h" +#include "libavcodec/eval.h" + +static const char *var_names[]= { + "PI", + "E", + "in_w", ///< input width + "out_w", ///< output width + "in_h", ///< input height + "out_h", ///< output height + "x", ///< x offset + "y", ///< y offset + NULL +}; + +enum var_name { + PI, + E, + IN_W, + OUT_W, + IN_H, + OUT_H, + X, + Y, + VARS_NB +}; typedef struct { + const AVClass *class; + char *out_w_expr, *out_h_expr; + char *x_expr, *y_expr; + + double var_values[VARS_NB]; int x, y, w, h; int cx, cy, cw, ch; @@ -32,33 +63,91 @@ int hsub, vsub; //< chroma subsampling } CropContext; +#define OFFSET(x) offsetof(CropContext, x) + +static const AVOption crop_options[] = { +{"out_w", "set output width expression", OFFSET(out_w_expr), FF_OPT_TYPE_STRING, 0, CHAR_MIN, CHAR_MAX}, +{"out_h", "set output height expression", OFFSET(out_h_expr), FF_OPT_TYPE_STRING, 0, CHAR_MIN, CHAR_MAX}, +{"x", "set x offset expression", OFFSET(x_expr), FF_OPT_TYPE_STRING, 0, CHAR_MIN, CHAR_MAX}, +{"y", "set y offset expression", OFFSET(y_expr), FF_OPT_TYPE_STRING, 0, CHAR_MIN, CHAR_MAX}, +{NULL}, +}; + +static const char *crop_get_name(void *ctx) +{ + return "crop"; +} + +static const AVClass crop_class = { + "CropContext", + crop_get_name, + crop_options +}; + static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) { CropContext *crop = ctx->priv; - /* default parameters */ - crop->x = 0; - crop->y = 0; - crop->w = -1; - crop->h = -1; + crop->class = &crop_class; + av_opt_set_defaults2(crop, 0, 0); + + crop->var_values[PI] = M_PI; + crop->var_values[E ] = M_E; - if(args) - sscanf(args, "%d:%d:%d:%d", &crop->x, &crop->y, &crop->w, &crop->h); + crop->out_w_expr = av_strdup("in_w"); + crop->out_h_expr = av_strdup("in_h"); + crop->x_expr = av_strdup("0"); + crop->y_expr = av_strdup("0"); + + if (args && av_set_options_string(crop, args, "=", ":") < 0) + return -1; return 0; } -static int config_input(AVFilterLink *link) +static av_cold void uninit(AVFilterContext *ctx) { - CropContext *crop = link->dst->priv; + CropContext *crop = ctx->priv; - crop->cx = FFMIN(crop->x, link->w - 1); - crop->cy = FFMIN(crop->y, link->h - 1); - crop->cw = FFMIN(crop->w, link->w - crop->cx); - crop->ch = FFMIN(crop->h, link->h - crop->cy); + av_free(crop->out_w_expr); + av_free(crop->out_h_expr); + av_free(crop->x_expr); + av_free(crop->y_expr); +} + +static double norm_max(double *x, double max) +{ + if (*x < 0) + *x = max + *x; + return av_clip(*x, 0, max); +} + +#define SET_EVAL_EXPRESSION(var__, expr__) \ + crop->var_values[var__] = ff_eval2((expr = crop->expr__), \ + crop->var_values, var_names, \ + NULL, NULL, NULL, NULL, NULL, &error); \ + if (error) { \ + av_log(crop, AV_LOG_ERROR, \ + "Error when evaluating the expression '%s': %s\n", expr, error); \ + return -1; \ + } - if(crop->cw <= 0) crop->cw = link->w - crop->cx; - if(crop->ch <= 0) crop->ch = link->h - crop->cy; +static int config_input(AVFilterLink *link) +{ + CropContext *crop = link->dst->priv; + const char *error = NULL, *expr; + crop->var_values[IN_W] = link->w; + crop->var_values[IN_H] = link->h; + + SET_EVAL_EXPRESSION(OUT_W, out_w_expr); + crop->cw = norm_max(&crop->var_values[OUT_W], link->w); + SET_EVAL_EXPRESSION(OUT_H, out_h_expr); + crop->ch = norm_max(&crop->var_values[OUT_H], link->h); + + SET_EVAL_EXPRESSION(X, x_expr); + crop->cx = norm_max(&crop->var_values[X], link->w - crop->cw); + SET_EVAL_EXPRESSION(Y, y_expr); + crop->cy = norm_max(&crop->var_values[Y], link->h - crop->ch); switch(link->format) { case PIX_FMT_RGB32: @@ -150,6 +239,7 @@ .priv_size = sizeof(CropContext), .init = init, + .uninit = uninit, .inputs = (AVFilterPad[]) {{ .name = "default", .type = CODEC_TYPE_VIDEO, Index: ffmpeg-vfilters/ffmpeg/tests/codec-regression.sh =================================================================== --- ffmpeg-vfilters.orig/ffmpeg/tests/codec-regression.sh 2009-10-04 22:21:32.000000000 +0200 +++ ffmpeg-vfilters/ffmpeg/tests/codec-regression.sh 2009-10-04 22:39:27.000000000 +0200 @@ -673,16 +673,16 @@ } do_lavfi "null" "null" -do_lavfi "crop" "crop=100:100:-1:-1" -do_lavfi "crop_scale" "crop=100:100,scale=200:-1" -do_lavfi "crop_vflip" "crop=100:100,vflip" +do_lavfi "crop" "crop=out_w=-100:out_h=-100:x=in_w:y=in_h" +do_lavfi "crop_scale" "crop=out_w=-100:out_h=-100:x=in_w:y=in_h,scale=200:-1" +do_lavfi "crop_vflip" "crop=out_w=-100:out_h=-100:x=in_w:y=in_h,vflip" do_lavfi "scale200" "scale=200:200" do_lavfi "scale500" "scale=500:500" do_lavfi "vflip" "vflip" -do_lavfi "vflip_crop" "vflip,crop=100:100" +do_lavfi "vflip_crop" "vflip,crop=out_w=-100:out_h=-100:x=in_w:y=in_h" do_lavfi "vflip_vflip" "vflip,vflip" do_lavfi "pad_pad" "pad=out_w=in_w+20:out_h=in_h+20:color=red,pad=out_w=in_w+20:out_h=in_h+20:color=blue" -do_lavfi "crop_scale_pad" "crop=100:100,scale=200:-1,pad=out_w=in_w+20:out_h=in_h+20:color=red" +do_lavfi "crop_scale_pad" "crop=out_w=-100:out_h=-100:x=in_w:y=in_h,scale=200:-1,pad=out_w=in_w+20:out_h=in_h+20:color=red" do_lavfi "vflip_pad" "vflip,pad=out_w=in_w+20:y=0:out_h=in_h+100" do_lavfi "pad_vflip" "pad=out_w=in_w+20:y=0:out_h=in_h+100,vflip"
_______________________________________________ FFmpeg-soc mailing list FFmpeg-soc@mplayerhq.hu https://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-soc