pad: make the filter parametric

Signed-off-by: Stefano Sabatini <stefano.sabatini-lala@poste.it>
Signed-off-by: Anton Khirnov <anton@khirnov.net>
This commit is contained in:
Stefano Sabatini 2011-04-17 17:19:05 +02:00 committed by Anton Khirnov
parent 0bbb28c75b
commit 73a4f7c21b
2 changed files with 162 additions and 9 deletions

View File

@ -753,6 +753,39 @@ given coordinates @var{x}, @var{y}.
It accepts the following parameters: It accepts the following parameters:
@var{width}:@var{height}:@var{x}:@var{y}:@var{color}. @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. Follows the description of the accepted parameters.
@table @option @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 value for @var{width} or @var{height} is 0, the corresponding input size
is used for the output. 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. The default value of @var{width} and @var{height} is 0.
@item x, y @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 Specify the offsets where to place the input image in the padded area
with respect to the top/left border of the output image. 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. The default value of @var{x} and @var{y} is 0.
@item color @item color
@ -780,13 +819,29 @@ The default value of @var{color} is "black".
@end table @end table
For example: Some examples follow:
@example @example
# Add paddings with color "violet" to the input video. Output video # 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 # size is 640x480, the top-left corner of the input video is placed at
# column 0, row 40. # column 0, row 40.
pad=640:480:0:40:violet 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 @end example
@section pixdesctest @section pixdesctest

View File

@ -25,6 +25,8 @@
*/ */
#include "avfilter.h" #include "avfilter.h"
#include "libavutil/avstring.h"
#include "libavutil/eval.h"
#include "libavutil/pixdesc.h" #include "libavutil/pixdesc.h"
#include "libavutil/colorspace.h" #include "libavutil/colorspace.h"
#include "libavutil/avassert.h" #include "libavutil/avassert.h"
@ -32,6 +34,38 @@
#include "libavutil/parseutils.h" #include "libavutil/parseutils.h"
#include "drawutils.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 int query_formats(AVFilterContext *ctx)
{ {
static const enum PixelFormat pix_fmts[] = { 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 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 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 color[4]; ///< color expressed either in YUVA or RGBA colorspace for the padding area
uint8_t *line[4]; uint8_t *line[4];
int line_step[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; PadContext *pad = ctx->priv;
char color_string[128] = "black"; 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) 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) if (av_parse_color(pad->color, color_string, -1, ctx) < 0)
return AVERROR(EINVAL); 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; return 0;
} }
@ -102,11 +141,64 @@ static int config_input(AVFilterLink *inlink)
PadContext *pad = ctx->priv; PadContext *pad = ctx->priv;
const AVPixFmtDescriptor *pix_desc = &av_pix_fmt_descriptors[inlink->format]; const AVPixFmtDescriptor *pix_desc = &av_pix_fmt_descriptors[inlink->format];
uint8_t rgba_color[4]; 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->hsub = pix_desc->log2_chroma_w;
pad->vsub = pix_desc->log2_chroma_h; 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) if (!pad->w)
pad->w = inlink->w; pad->w = inlink->w;
if (!pad->h) if (!pad->h)
@ -140,6 +232,12 @@ static int config_input(AVFilterLink *inlink)
} }
return 0; 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) static int config_output(AVFilterLink *outlink)