[libav-devel] [PATCH] lavfi: extend vf_overlay

Luca Barbato lu_zero at gentoo.org
Fri Nov 25 23:03:15 CET 2011


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
+
+ at 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}
+
+ at item n
+the number of frames processed, starting from 0
+
+ at 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



More information about the libav-devel mailing list