Skip to content

Commit

Permalink
pad: make the filter parametric
Browse files Browse the repository at this point in the history
Signed-off-by: Stefano Sabatini <stefano.sabatini-lala@poste.it>
Signed-off-by: Anton Khirnov <anton@khirnov.net>
  • Loading branch information
Stefano Sabatini authored and elenril committed Apr 26, 2011
1 parent 0bbb28c commit 73a4f7c
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 9 deletions.
57 changes: 56 additions & 1 deletion doc/filters.texi
Expand Up @@ -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
Expand All @@ -762,13 +795,19 @@ 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

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
Expand All @@ -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
Expand Down
114 changes: 106 additions & 8 deletions libavfilter/vf_pad.c
Expand Up @@ -25,13 +25,47 @@
*/

#include "avfilter.h"
#include "libavutil/avstring.h"
#include "libavutil/eval.h"
#include "libavutil/pixdesc.h"
#include "libavutil/colorspace.h"
#include "libavutil/avassert.h"
#include "libavutil/imgutils.h"
#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[] = {
Expand All @@ -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];
Expand All @@ -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;
}

Expand All @@ -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<<pad->hsub;
var_values[VAR_VSUB] = 2<<pad->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)
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 73a4f7c

Please sign in to comment.