From 73a4f7c21bbb179f7542d8a5fedf55fd894fa9da Mon Sep 17 00:00:00 2001 From: Stefano Sabatini Date: Sun, 17 Apr 2011 17:19:05 +0200 Subject: [PATCH] pad: make the filter parametric Signed-off-by: Stefano Sabatini Signed-off-by: Anton Khirnov --- doc/filters.texi | 57 +++++++++++++++++++++- libavfilter/vf_pad.c | 114 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 162 insertions(+), 9 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index 48c03f1ed8..35b61d170d 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -753,6 +753,39 @@ given coordinates @var{x}, @var{y}. It accepts the following parameters: @var{width}:@var{height}:@var{x}:@var{y}:@var{color}. +The parameters @var{width}, @var{height}, @var{x}, and @var{y} are +expressions containing the following constants: + +@table @option +@item E, PI, PHI +the corresponding mathematical approximated values for e +(euler number), pi (greek PI), phi (golden ratio) + +@item in_w, in_h +the input video width and heigth + +@item iw, ih +same as @var{in_w} and @var{in_h} + +@item out_w, out_h +the output width and heigth, that is the size of the padded area as +specified by the @var{width} and @var{height} expressions + +@item ow, oh +same as @var{out_w} and @var{out_h} + +@item x, y +x and y offsets as specified by the @var{x} and @var{y} +expressions, or NAN if not yet specified + +@item a +input display aspect ratio, same as @var{iw} / @var{ih} + +@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 + Follows the description of the accepted parameters. @table @option @@ -762,6 +795,9 @@ 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. +The @var{width} expression can reference the value set by the +@var{height} expression, and viceversa. + The default value of @var{width} and @var{height} is 0. @item x, y @@ -769,6 +805,9 @@ The default value of @var{width} and @var{height} is 0. Specify the offsets where to place the input image in the padded area with respect to the top/left border of the output image. +The @var{x} expression can reference the value set by the @var{y} +expression, and viceversa. + The default value of @var{x} and @var{y} is 0. @item color @@ -780,13 +819,29 @@ The default value of @var{color} is "black". @end table -For example: +Some examples follow: @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=640:480:0:40:violet + +# 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" + +# 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" + +# pad the input to get a final w/h ratio of 16:9 +pad="ih*16/9:ih:(ow-iw)/2:(oh-ih)/2" + +# 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" @end example @section pixdesctest diff --git a/libavfilter/vf_pad.c b/libavfilter/vf_pad.c index 4f8e6450e3..18873b8837 100644 --- a/libavfilter/vf_pad.c +++ b/libavfilter/vf_pad.c @@ -25,6 +25,8 @@ */ #include "avfilter.h" +#include "libavutil/avstring.h" +#include "libavutil/eval.h" #include "libavutil/pixdesc.h" #include "libavutil/colorspace.h" #include "libavutil/avassert.h" @@ -32,6 +34,38 @@ #include "libavutil/parseutils.h" #include "drawutils.h" +static const char *var_names[] = { + "PI", + "PHI", + "E", + "in_w", "iw", + "in_h", "ih", + "out_w", "ow", + "out_h", "oh", + "x", + "y", + "a", + "hsub", + "vsub", + NULL +}; + +enum var_name { + VAR_PI, + VAR_PHI, + VAR_E, + VAR_IN_W, VAR_IW, + VAR_IN_H, VAR_IH, + VAR_OUT_W, VAR_OW, + VAR_OUT_H, VAR_OH, + VAR_X, + VAR_Y, + VAR_A, + VAR_HSUB, + VAR_VSUB, + VARS_NB +}; + static int query_formats(AVFilterContext *ctx) { static const enum PixelFormat pix_fmts[] = { @@ -58,6 +92,11 @@ typedef struct { int x, y; ///< offsets of the input area with respect to the padded area int in_w, in_h; ///< width and height for the padded input video, which has to be aligned to the chroma values in order to avoid chroma issues + char w_expr[256]; ///< width expression string + char h_expr[256]; ///< height expression string + char x_expr[256]; ///< width expression string + char y_expr[256]; ///< height expression string + uint8_t color[4]; ///< color expressed either in YUVA or RGBA colorspace for the padding area uint8_t *line[4]; int line_step[4]; @@ -70,18 +109,18 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) PadContext *pad = ctx->priv; char color_string[128] = "black"; + av_strlcpy(pad->w_expr, "iw", sizeof(pad->w_expr)); + av_strlcpy(pad->h_expr, "ih", sizeof(pad->h_expr)); + av_strlcpy(pad->x_expr, "0" , sizeof(pad->w_expr)); + av_strlcpy(pad->y_expr, "0" , sizeof(pad->h_expr)); + if (args) - sscanf(args, "%d:%d:%d:%d:%s", &pad->w, &pad->h, &pad->x, &pad->y, color_string); + sscanf(args, "%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255s", + pad->w_expr, pad->h_expr, pad->x_expr, pad->y_expr, color_string); if (av_parse_color(pad->color, color_string, -1, ctx) < 0) return AVERROR(EINVAL); - /* sanity check params */ - if (pad->w < 0 || pad->h < 0) { - av_log(ctx, AV_LOG_ERROR, "Negative size values are not acceptable.\n"); - return AVERROR(EINVAL); - } - return 0; } @@ -102,11 +141,64 @@ static int config_input(AVFilterLink *inlink) PadContext *pad = ctx->priv; const AVPixFmtDescriptor *pix_desc = &av_pix_fmt_descriptors[inlink->format]; uint8_t rgba_color[4]; - int is_packed_rgba; + int ret, is_packed_rgba; + double var_values[VARS_NB], res; + char *expr; pad->hsub = pix_desc->log2_chroma_w; pad->vsub = pix_desc->log2_chroma_h; + var_values[VAR_PI] = M_PI; + var_values[VAR_PHI] = M_PHI; + var_values[VAR_E] = M_E; + var_values[VAR_IN_W] = var_values[VAR_IW] = inlink->w; + var_values[VAR_IN_H] = var_values[VAR_IH] = inlink->h; + var_values[VAR_OUT_W] = var_values[VAR_OW] = NAN; + var_values[VAR_OUT_H] = var_values[VAR_OH] = NAN; + var_values[VAR_A] = (float) inlink->w / inlink->h; + var_values[VAR_HSUB] = 1<hsub; + var_values[VAR_VSUB] = 2<vsub; + + /* evaluate width and height */ + av_expr_parse_and_eval(&res, (expr = pad->w_expr), + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx); + pad->w = var_values[VAR_OUT_W] = var_values[VAR_OW] = res; + if ((ret = av_expr_parse_and_eval(&res, (expr = pad->h_expr), + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0) + goto eval_fail; + pad->h = var_values[VAR_OUT_H] = var_values[VAR_OH] = res; + /* evaluate the width again, as it may depend on the evaluated output height */ + if ((ret = av_expr_parse_and_eval(&res, (expr = pad->w_expr), + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0) + goto eval_fail; + pad->w = var_values[VAR_OUT_W] = var_values[VAR_OW] = res; + + /* evaluate x and y */ + av_expr_parse_and_eval(&res, (expr = pad->x_expr), + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx); + pad->x = var_values[VAR_X] = res; + if ((ret = av_expr_parse_and_eval(&res, (expr = pad->y_expr), + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0) + goto eval_fail; + pad->y = var_values[VAR_Y] = res; + /* evaluate x again, as it may depend on the evaluated y value */ + if ((ret = av_expr_parse_and_eval(&res, (expr = pad->x_expr), + var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0) + goto eval_fail; + pad->x = var_values[VAR_X] = res; + + /* sanity check params */ + if (pad->w < 0 || pad->h < 0 || pad->x < 0 || pad->y < 0) { + av_log(ctx, AV_LOG_ERROR, "Negative values are not acceptable.\n"); + return AVERROR(EINVAL); + } + if (!pad->w) pad->w = inlink->w; if (!pad->h) @@ -140,6 +232,12 @@ static int config_input(AVFilterLink *inlink) } return 0; + +eval_fail: + av_log(NULL, AV_LOG_ERROR, + "Error when evaluating the expression '%s'\n", expr); + return ret; + } static int config_output(AVFilterLink *outlink)