+static inline int normalize_xy(double d, int chroma_sub)
+{
+ if (isnan(d))
+ return INT_MAX;
+ return (int)d & ~((1 << chroma_sub) - 1);
+}
+
+enum EvalTarget { EVAL_XY, EVAL_ENABLE, EVAL_ALL };
+
+static void eval_expr(AVFilterContext *ctx, enum EvalTarget eval_tgt)
+{
+ OverlayContext *over = ctx->priv;
+
+ if (eval_tgt == EVAL_XY || eval_tgt == EVAL_ALL) {
+ 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);
+ over->x = normalize_xy(over->var_values[VAR_X], over->hsub);
+ over->y = normalize_xy(over->var_values[VAR_Y], over->vsub);
+ }
+ if (eval_tgt == EVAL_ENABLE || eval_tgt == EVAL_ALL) {
+ over->enable = av_expr_eval(over->enable_pexpr, over->var_values, NULL);
+ }
+}
+
+static int set_expr(AVExpr **pexpr, const char *expr, void *log_ctx)
+{
+ int ret;
+
+ if (*pexpr)
+ av_expr_free(*pexpr);
+ *pexpr = NULL;
+ ret = av_expr_parse(pexpr, expr, var_names,
+ NULL, NULL, NULL, NULL, 0, log_ctx);
+ if (ret < 0)
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Error when evaluating the expression '%s'\n", expr);
+ return ret;
+}
+
+static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
+ char *res, int res_len, int flags)
+{
+ OverlayContext *over = ctx->priv;
+ int ret;
+
+ if (!strcmp(cmd, "x"))
+ ret = set_expr(&over->x_pexpr, args, ctx);
+ else if (!strcmp(cmd, "y"))
+ ret = set_expr(&over->y_pexpr, args, ctx);
+ else if (!strcmp(cmd, "enable"))
+ ret = set_expr(&over->enable_pexpr, args, ctx);
+ else
+ ret = AVERROR(ENOSYS);
+
+ if (ret < 0)
+ return ret;
+
+ if (over->eval_mode == EVAL_MODE_INIT) {
+ eval_expr(ctx, EVAL_ALL);
+ av_log(ctx, AV_LOG_VERBOSE, "x:%f xi:%d y:%f yi:%d enable:%f\n",
+ over->var_values[VAR_X], over->x,
+ over->var_values[VAR_Y], over->y,
+ over->enable);
+ }
+ return ret;
+}
+