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

Reply via email to