Commit 84f571e3 authored by Mark Visser's avatar Mark Visser

enabled expressions on x, y, w, h and t parameters for drawgrid and drawbox, added examples

parent 7fff3df6
...@@ -2886,11 +2886,11 @@ This filter accepts the following options: ...@@ -2886,11 +2886,11 @@ This filter accepts the following options:
@table @option @table @option
@item x @item x
@item y @item y
Specify the top left corner coordinates of the box. Default to 0. The expressions which specify the top left corner coordinates of the box. Default to 0.
@item width, w @item width, w
@item height, h @item height, h
Specify the width and height of the box, if 0 they are interpreted as The expressions which specify the width and height of the box, if 0 they are interpreted as
the input width and height. Default to 0. the input width and height. Default to 0.
@item color, c @item color, c
...@@ -2900,7 +2900,44 @@ value @code{invert} is used, the box edge color is the same as the ...@@ -2900,7 +2900,44 @@ value @code{invert} is used, the box edge color is the same as the
video with inverted luma. video with inverted luma.
@item thickness, t @item thickness, t
Set the thickness of the box edge. Default value is @code{3}. The expression which sets the thickness of the box edge. Default value is @code{3}.
See below for the list of accepted constants.
@end table
The parameters for @var{x}, @var{y}, @var{w} and @var{h} and @var{t} are expressions containing the
following constants:
@table @option
@item dar
The input display aspect ratio, it is the same as (@var{w} / @var{h}) * @var{sar}.
@item hsub
@item vsub
horizontal and vertical chroma subsample values. For example for the
pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
@item in_h, ih
@item in_w, iw
The input width and height.
@item sar
The input sample aspect ratio.
@item x
@item y
The x and y offset coordinates where the box is drawn.
@item w
@item h
The width and height of the drawn box.
@item t
The thickness of the drawn box.
These constants allow the @var{x}, @var{y}, @var{w}, @var{h} and @var{t} expressions to refer to
each other, so you may for example specify @code(y=x/dar} or @code(h=w/dar).
@end table @end table
@subsection Examples @subsection Examples
...@@ -2928,6 +2965,12 @@ Fill the box with pink color: ...@@ -2928,6 +2965,12 @@ Fill the box with pink color:
@example @example
drawbox=x=10:y=10:w=100:h=100:color=pink@@0.5:t=max drawbox=x=10:y=10:w=100:h=100:color=pink@@0.5:t=max
@end example @end example
@item
Draw a 2-pixel red 2.40:1 mask:
@example
drawbox=x=-t:y=0.5*(ih-iw/2.4)-t:w=iw+t*2:h=iw/2.4+t*2:t=2:c=red
@end example
@end itemize @end itemize
@section drawgrid @section drawgrid
...@@ -2939,11 +2982,11 @@ This filter accepts the following options: ...@@ -2939,11 +2982,11 @@ This filter accepts the following options:
@table @option @table @option
@item x @item x
@item y @item y
Specify the coordinates of some point of grid intersection (meant to configure offset). Both default to 0. The expressions which specify the coordinates of some point of grid intersection (meant to configure offset). Both default to 0.
@item width, w @item width, w
@item height, h @item height, h
Specify the width and height of the grid cell, if 0 they are interpreted as the The expressions which specify the width and height of the grid cell, if 0 they are interpreted as the
input width and height, respectively, minus @code{thickness}, so image gets input width and height, respectively, minus @code{thickness}, so image gets
framed. Default to 0. framed. Default to 0.
...@@ -2956,7 +2999,44 @@ Note that you can append opacity value (in range of 0.0 - 1.0) ...@@ -2956,7 +2999,44 @@ Note that you can append opacity value (in range of 0.0 - 1.0)
to color name after @@ sign. to color name after @@ sign.
@item thickness, t @item thickness, t
Set the thickness of the grid line. Default value is @code{1}. The expression which sets the thickness of the grid line. Default value is @code{1}.
See below for the list of accepted constants.
@end table
The parameters for @var{x}, @var{y}, @var{w} and @var{h} and @var{t} are expressions containing the
following constants:
@table @option
@item dar
The input display aspect ratio, it is the same as (@var{w} / @var{h}) * @var{sar}.
@item hsub
@item vsub
horizontal and vertical chroma subsample values. For example for the
pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
@item in_h, ih
@item in_w, iw
The input grid cell width and height.
@item sar
The input sample aspect ratio.
@item x
@item y
The x and y coordinates of some point of grid intersection (meant to configure offset).
@item w
@item h
The width and height of the drawn cell.
@item t
The thickness of the drawn cell.
These constants allow the @var{x}, @var{y}, @var{w}, @var{h} and @var{t} expressions to refer to
each other, so you may for example specify @code(y=x/dar} or @code(h=w/dar).
@end table @end table
@subsection Examples @subsection Examples
...@@ -2967,6 +3047,12 @@ Draw a grid with cell 100x100 pixels, thickness 2 pixels, with color red and an ...@@ -2967,6 +3047,12 @@ Draw a grid with cell 100x100 pixels, thickness 2 pixels, with color red and an
@example @example
drawgrid=width=100:height=100:thickness=2:color=red@@0.5 drawgrid=width=100:height=100:thickness=2:color=red@@0.5
@end example @end example
@item
Draw a white 3x3 grid with an opacity of 50%:
@example
drawgrid=w=iw/3:h=ih/3:t=2:c=white@@0.5
@end example
@end itemize @end itemize
@anchor{drawtext} @anchor{drawtext}
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "libavutil/colorspace.h" #include "libavutil/colorspace.h"
#include "libavutil/common.h" #include "libavutil/common.h"
#include "libavutil/opt.h" #include "libavutil/opt.h"
#include "libavutil/eval.h"
#include "libavutil/pixdesc.h" #include "libavutil/pixdesc.h"
#include "libavutil/parseutils.h" #include "libavutil/parseutils.h"
#include "avfilter.h" #include "avfilter.h"
...@@ -35,18 +36,51 @@ ...@@ -35,18 +36,51 @@
#include "internal.h" #include "internal.h"
#include "video.h" #include "video.h"
static const char *const var_names[] = {
"dar",
"hsub", "vsub",
"in_h", "ih", ///< height of the input video
"in_w", "iw", ///< width of the input video
"sar",
"x",
"y",
"h", ///< height of the rendered box
"w", ///< width of the rendered box
"t",
NULL
};
enum { Y, U, V, A }; enum { Y, U, V, A };
enum var_name {
VAR_DAR,
VAR_HSUB, VAR_VSUB,
VAR_IN_H, VAR_IH,
VAR_IN_W, VAR_IW,
VAR_SAR,
VAR_X,
VAR_Y,
VAR_H,
VAR_W,
VAR_T,
VARS_NB
};
typedef struct { typedef struct {
const AVClass *class; const AVClass *class;
int x, y, w_opt, h_opt, w, h; int x, y, w, h;
int thickness; int thickness;
char *color_str; char *color_str;
unsigned char yuv_color[4]; unsigned char yuv_color[4];
int invert_color; ///< invert luma color int invert_color; ///< invert luma color
int vsub, hsub; ///< chroma subsampling int vsub, hsub; ///< chroma subsampling
char *x_expr, *y_expr; ///< expression for x and y
char *w_expr, *h_expr; ///< expression for width and height
char *t_expr; ///< expression for thickness
} DrawBoxContext; } DrawBoxContext;
static const int NUM_EXPR_EVALS = 5;
static av_cold int init(AVFilterContext *ctx) static av_cold int init(AVFilterContext *ctx)
{ {
DrawBoxContext *s = ctx->priv; DrawBoxContext *s = ctx->priv;
...@@ -83,20 +117,82 @@ static int query_formats(AVFilterContext *ctx) ...@@ -83,20 +117,82 @@ static int query_formats(AVFilterContext *ctx)
static int config_input(AVFilterLink *inlink) static int config_input(AVFilterLink *inlink)
{ {
DrawBoxContext *s = inlink->dst->priv; AVFilterContext *ctx = inlink->dst;
DrawBoxContext *s = ctx->priv;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
double var_values[VARS_NB], res;
char *expr;
int ret;
s->hsub = desc->log2_chroma_w; s->hsub = desc->log2_chroma_w;
s->vsub = desc->log2_chroma_h; s->vsub = desc->log2_chroma_h;
s->w = (s->w_opt > 0) ? s->w_opt : inlink->w; var_values[VAR_IN_H] = var_values[VAR_IH] = inlink->h;
s->h = (s->h_opt > 0) ? s->h_opt : inlink->h; var_values[VAR_IN_W] = var_values[VAR_IW] = inlink->w;
var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ? av_q2d(inlink->sample_aspect_ratio) : 1;
var_values[VAR_DAR] = (double)inlink->w / inlink->h * var_values[VAR_SAR];
var_values[VAR_HSUB] = s->hsub;
var_values[VAR_VSUB] = s->vsub;
var_values[VAR_X] = NAN;
var_values[VAR_Y] = NAN;
var_values[VAR_H] = NAN;
var_values[VAR_W] = NAN;
var_values[VAR_T] = NAN;
for (int i = 0; i <= NUM_EXPR_EVALS; i++) {
/* evaluate expressions, fail on last iteration */
if ((ret = av_expr_parse_and_eval(&res, (expr = s->x_expr),
var_names, var_values,
NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i == NUM_EXPR_EVALS)
goto fail;
s->x = var_values[VAR_X] = res;
if ((ret = av_expr_parse_and_eval(&res, (expr = s->y_expr),
var_names, var_values,
NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i == NUM_EXPR_EVALS)
goto fail;
s->y = var_values[VAR_Y] = res;
if ((ret = av_expr_parse_and_eval(&res, (expr = s->w_expr),
var_names, var_values,
NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i == NUM_EXPR_EVALS)
goto fail;
s->w = var_values[VAR_W] = res;
if ((ret = av_expr_parse_and_eval(&res, (expr = s->h_expr),
var_names, var_values,
NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i == NUM_EXPR_EVALS)
goto fail;
s->h = var_values[VAR_H] = res;
if ((ret = av_expr_parse_and_eval(&res, (expr = s->t_expr),
var_names, var_values,
NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i == NUM_EXPR_EVALS)
goto fail;
s->thickness = var_values[VAR_T] = res;
}
/* if w or h are zero, use the input w/h */
s->w = (s->w > 0) ? s->w : inlink->w;
s->h = (s->h > 0) ? s->h : inlink->h;
/* sanity check width and height */
if (s->w < 0 || s->h < 0) {
av_log(ctx, AV_LOG_ERROR, "Size values less than 0 are not acceptable.\n");
return AVERROR(EINVAL);
}
av_log(inlink->dst, AV_LOG_VERBOSE, "x:%d y:%d w:%d h:%d color:0x%02X%02X%02X%02X\n", av_log(ctx, AV_LOG_VERBOSE, "x:%d y:%d w:%d h:%d color:0x%02X%02X%02X%02X\n",
s->x, s->y, s->w, s->h, s->x, s->y, s->w, s->h,
s->yuv_color[Y], s->yuv_color[U], s->yuv_color[V], s->yuv_color[A]); s->yuv_color[Y], s->yuv_color[U], s->yuv_color[V], s->yuv_color[A]);
return 0; return 0;
fail:
av_log(NULL, AV_LOG_ERROR,
"Error when evaluating the expression '%s'.\n",
expr);
return ret;
} }
static int filter_frame(AVFilterLink *inlink, AVFrame *frame) static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
...@@ -140,16 +236,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) ...@@ -140,16 +236,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
#if CONFIG_DRAWBOX_FILTER #if CONFIG_DRAWBOX_FILTER
static const AVOption drawbox_options[] = { static const AVOption drawbox_options[] = {
{ "x", "set horizontal position of the left box edge", OFFSET(x), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS }, { "x", "set horizontal position of the left box edge", OFFSET(x_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ "y", "set vertical position of the top box edge", OFFSET(y), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS }, { "y", "set vertical position of the top box edge", OFFSET(y_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ "width", "set width of the box", OFFSET(w_opt), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, { "width", "set width of the box", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ "w", "set width of the box", OFFSET(w_opt), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, { "w", "set width of the box", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ "height", "set height of the box", OFFSET(h_opt), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, { "height", "set height of the box", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ "h", "set height of the box", OFFSET(h_opt), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, { "h", "set height of the box", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ "color", "set color of the box", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS }, { "color", "set color of the box", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ "c", "set color of the box", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS }, { "c", "set color of the box", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ "thickness", "set the box thickness", OFFSET(thickness), AV_OPT_TYPE_INT, { .i64 = 3 }, 0, INT_MAX, FLAGS }, { "thickness", "set the box thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, { .str="3" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ "t", "set the box thickness", OFFSET(thickness), AV_OPT_TYPE_INT, { .i64 = 3 }, 0, INT_MAX, FLAGS }, { "t", "set the box thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, { .str="3" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ NULL } { NULL }
}; };
...@@ -248,16 +344,16 @@ static int drawgrid_filter_frame(AVFilterLink *inlink, AVFrame *frame) ...@@ -248,16 +344,16 @@ static int drawgrid_filter_frame(AVFilterLink *inlink, AVFrame *frame)
} }
static const AVOption drawgrid_options[] = { static const AVOption drawgrid_options[] = {
{ "x", "set horizontal offset", OFFSET(x), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS }, { "x", "set horizontal offset", OFFSET(x_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ "y", "set vertical offset", OFFSET(y), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS }, { "y", "set vertical offset", OFFSET(y_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ "width", "set width of grid cell", OFFSET(w_opt), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, { "width", "set width of grid cell", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ "w", "set width of grid cell", OFFSET(w_opt), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, { "w", "set width of grid cell", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ "height", "set height of grid cell", OFFSET(h_opt), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, { "height", "set height of grid cell", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ "h", "set height of grid cell", OFFSET(h_opt), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, { "h", "set height of grid cell", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ "color", "set color of the grid", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS }, { "color", "set color of the grid", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ "c", "set color of the grid", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS }, { "c", "set color of the grid", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS },
{ "thickness", "set grid line thickness", OFFSET(thickness), AV_OPT_TYPE_INT, {.i64=1}, 0, INT_MAX, FLAGS }, { "thickness", "set grid line thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, {.str="1"}, CHAR_MIN, CHAR_MAX, FLAGS },
{ "t", "set grid line thickness", OFFSET(thickness), AV_OPT_TYPE_INT, {.i64=1}, 0, INT_MAX, FLAGS }, { "t", "set grid line thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, {.str="1"}, CHAR_MIN, CHAR_MAX, FLAGS },
{ NULL } { NULL }
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment