Introduce "n", number of processed frame and "t" timestamp expressed in
seconds and have "x" and "y" variables evaluated each frame.
---
doc/filters.texi | 12 +++++
libavfilter/vf_overlay.c | 121 ++++++++++++++++++++++++++++++----------------
2 files changed, 91 insertions(+), 42 deletions(-)
diff --git a/doc/filters.texi b/doc/filters.texi
index 4b38813..3abf64a 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -1062,6 +1062,11 @@ It accepts the parameters: @var{x}:@var{y}.
the following parameters:
@table @option
+
+@item x, y
+the computed values for @var{x} and @var{y}. They are evaluated for
+each new frame.
+
@item main_w, main_h
main input width and height
@@ -1073,6 +1078,13 @@ overlay input width and height
@item w, h
same as @var{overlay_w} and @var{overlay_h}
+
+@item n
+the number of frames processed, starting from 0
+
+@item t
+timestamp expressed in seconds, NAN if the input timestamp is unknown
+
@end table
Be aware that frames are taken from each input video in timestamp
diff --git a/libavfilter/vf_overlay.c b/libavfilter/vf_overlay.c
index 39b2375..eba2eb5 100644
--- a/libavfilter/vf_overlay.c
+++ b/libavfilter/vf_overlay.c
@@ -41,6 +41,10 @@ static const char *var_names[] = {
"main_h", "H", ///< height of the main video
"overlay_w", "w", ///< width of the overlay video
"overlay_h", "h", ///< height of the overlay video
+ "x",
+ "y",
+ "n", ///< number of processed frames
+ "t", ///< timestamp expressed in seconds
NULL
};
@@ -52,6 +56,10 @@ enum var_name {
VAR_MAIN_H, VAR_MH,
VAR_OVERLAY_W, VAR_OW,
VAR_OVERLAY_H, VAR_OH,
+ VAR_X,
+ VAR_Y,
+ VAR_N,
+ VAR_T,
VAR_VARS_NB
};
@@ -60,6 +68,7 @@ enum var_name {
typedef struct {
int x, y; ///< position of overlayed picture
+ int w, h;
AVFilterBufferRef *overpicref;
@@ -67,6 +76,8 @@ typedef struct {
int hsub, vsub; ///< chroma subsampling values
char x_expr[256], y_expr[256];
+ AVExpr *x_pexpr, *y_pexpr; /* parsed expressions for x and y */
+ double var_values[VAR_VARS_NB];
} OverlayContext;
static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
@@ -120,60 +131,41 @@ static int config_input_overlay(AVFilterLink *inlink)
{
AVFilterContext *ctx = inlink->dst;
OverlayContext *over = inlink->dst->priv;
- char *expr;
- double var_values[VAR_VARS_NB], res;
int ret;
/* Finish the configuration by evaluating the expressions
now when both inputs are configured. */
- var_values[VAR_E ] = M_E;
- var_values[VAR_PHI] = M_PHI;
- var_values[VAR_PI ] = M_PI;
-
- var_values[VAR_MAIN_W ] = var_values[VAR_MW] = ctx->inputs[MAIN ]->w;
- var_values[VAR_MAIN_H ] = var_values[VAR_MH] = ctx->inputs[MAIN ]->h;
- var_values[VAR_OVERLAY_W] = var_values[VAR_OW] = ctx->inputs[OVERLAY]->w;
- var_values[VAR_OVERLAY_H] = var_values[VAR_OH] = ctx->inputs[OVERLAY]->h;
-
- if ((ret = av_expr_parse_and_eval(&res, (expr = over->x_expr), var_names,
var_values,
- NULL, NULL, NULL, NULL, NULL, 0, ctx)) <
0)
- goto fail;
- over->x = res;
- if ((ret = av_expr_parse_and_eval(&res, (expr = over->y_expr), var_names,
var_values,
- NULL, NULL, NULL, NULL, NULL, 0, ctx)))
- goto fail;
- over->y = res;
- /* x may depend on y */
- if ((ret = av_expr_parse_and_eval(&res, (expr = over->x_expr), var_names,
var_values,
- NULL, NULL, NULL, NULL, NULL, 0, ctx)) <
0)
- goto fail;
- over->x = res;
+ over->var_values[VAR_E ] = M_E;
+ over->var_values[VAR_PHI] = M_PHI;
+ over->var_values[VAR_PI ] = M_PI;
+
+ over->var_values[VAR_MAIN_W ] =
+ over->var_values[VAR_MW] = ctx->inputs[MAIN ]->w;
+ over->var_values[VAR_MAIN_H ] =
+ over->var_values[VAR_MH] = ctx->inputs[MAIN ]->h;
+ over->var_values[VAR_OVERLAY_W] =
+ over->var_values[VAR_OW] = ctx->inputs[OVERLAY]->w;
+ over->var_values[VAR_OVERLAY_H] =
+ over->var_values[VAR_OH] = ctx->inputs[OVERLAY]->h;
+ over->var_values[VAR_X] = 0;
+ over->var_values[VAR_Y] = 0;
+ over->var_values[VAR_N] = 0;
+ over->var_values[VAR_T] = NAN;
+
+ if ((ret = av_expr_parse(&over->x_pexpr, over->x_expr, var_names,
+ NULL, NULL, NULL, NULL, 0, ctx)) < 0 ||
+ (ret = av_expr_parse(&over->y_pexpr, over->y_expr, var_names,
+ NULL, NULL, NULL, NULL, 0, ctx)) < 0)
+ return AVERROR(EINVAL);
av_log(ctx, AV_LOG_INFO,
- "main w:%d h:%d fmt:%s overlay x:%d y:%d w:%d h:%d fmt:%s\n",
+ "main w:%d h:%d fmt:%s overlay w:%d h:%d fmt:%s\n",
ctx->inputs[MAIN]->w, ctx->inputs[MAIN]->h,
av_pix_fmt_descriptors[ctx->inputs[MAIN]->format].name,
- over->x, over->y,
ctx->inputs[OVERLAY]->w, ctx->inputs[OVERLAY]->h,
av_pix_fmt_descriptors[ctx->inputs[OVERLAY]->format].name);
- if (over->x < 0 || over->y < 0 ||
- over->x + var_values[VAR_OVERLAY_W] > var_values[VAR_MAIN_W] ||
- over->y + var_values[VAR_OVERLAY_H] > var_values[VAR_MAIN_H]) {
- av_log(ctx, AV_LOG_ERROR,
- "Overlay area (%d,%d)<->(%d,%d) not within the main area
(0,0)<->(%d,%d) or zero-sized\n",
- over->x, over->y,
- (int)(over->x + var_values[VAR_OVERLAY_W]),
- (int)(over->y + var_values[VAR_OVERLAY_H]),
- (int)var_values[VAR_MAIN_W], (int)var_values[VAR_MAIN_H]);
- return AVERROR(EINVAL);
- }
return 0;
-
-fail:
- av_log(NULL, AV_LOG_ERROR,
- "Error when evaluating the expression '%s'\n", expr);
- return ret;
}
static int config_output(AVFilterLink *outlink)
@@ -206,6 +198,21 @@ static AVFilterBufferRef *get_video_buffer(AVFilterLink
*link, int perms, int w,
return avfilter_get_video_buffer(link->dst->outputs[0], perms, w, h);
}
+static inline int normalize_double(int *n, double d)
+{
+ int ret = 0;
+
+ if (isnan(d)) {
+ ret = AVERROR(EINVAL);
+ } else if (d > INT_MAX || d < INT_MIN) {
+ *n = d > INT_MAX ? INT_MAX : INT_MIN;
+ ret = AVERROR(EINVAL);
+ } else
+ *n = round(d);
+
+ return ret;
+}
+
static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
{
AVFilterBufferRef *outpicref = avfilter_ref_buffer(inpicref, ~0);
@@ -227,6 +234,32 @@ static void start_frame(AVFilterLink *inlink,
AVFilterBufferRef *inpicref)
over->overpicref = old;
}
+ over->var_values[VAR_T] = outpicref->pts == AV_NOPTS_VALUE ?
+ NAN : outpicref->pts * av_q2d(inlink->time_base);
+ over->var_values[VAR_X] =
+ av_expr_eval(over->x_pexpr, over->var_values, NULL);
+ over->var_values[VAR_Y] =
+ av_expr_eval(over->y_pexpr, over->var_values, NULL);
+ over->var_values[VAR_X] =
+ av_expr_eval(over->x_pexpr, over->var_values, NULL);
+
+ normalize_double(&over->x, over->var_values[VAR_X]);
+ normalize_double(&over->y, over->var_values[VAR_Y]);
+
+ if (over->x < 0) over->x = 0;
+ if (over->y < 0) over->y = 0;
+ if ((unsigned)over->x + (unsigned)over->w > inlink->w)
+ over->x = inlink->w - over->w;
+ if ((unsigned)over->y + (unsigned)over->h > inlink->h)
+ over->y = inlink->h - over->h;
+
+ over->x &= ~((1 << over->hsub) - 1);
+ over->y &= ~((1 << over->vsub) - 1);
+
+ av_dlog(ctx, "n:%d t:%f x:%d y:%d x+w:%d y+h:%d\n",
+ (int)over->var_values[VAR_N], over->var_values[VAR_T],
+ over->x, over->y, over->x+over->w, over->y+over->h);
+
avfilter_start_frame(inlink->dst->outputs[0], outpicref);
}
@@ -337,6 +370,10 @@ static void draw_slice(AVFilterLink *inlink, int y, int h,
int slice_dir)
static void end_frame(AVFilterLink *inlink)
{
+ OverlayContext *over = inlink->dst->priv;
+
+ over->var_values[VAR_N] += 1.0;
+
avfilter_end_frame(inlink->dst->outputs[0]);
avfilter_unref_buffer(inlink->cur_buf);
}
--
1.7.8.rc1
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel