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
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-soc