+static int config_props(AVFilterLink *outlink);
+
+static int check_exprs(AVFilterContext *ctx)
+{
+ ScaleContext *scale = ctx->priv;
+ unsigned vars_w[VARS_NB] = { 0 }, vars_h[VARS_NB] = { 0 };
+
+ if (!scale->w_pexpr && !scale->h_pexpr)
+ return AVERROR(EINVAL);
+
+ if (scale->w_pexpr)
+ av_expr_count_vars(scale->w_pexpr, vars_w, VARS_NB);
+ if (scale->h_pexpr)
+ av_expr_count_vars(scale->h_pexpr, vars_h, VARS_NB);
+
+ if (vars_w[VAR_OUT_W] || vars_w[VAR_OW]) {
+ av_log(ctx, AV_LOG_ERROR, "Width expression cannot be self-referencing: '%s'.\n", scale->w_expr);
+ return AVERROR(EINVAL);
+ }
+
+ if (vars_h[VAR_OUT_H] || vars_h[VAR_OH]) {
+ av_log(ctx, AV_LOG_ERROR, "Height expression cannot be self-referencing: '%s'.\n", scale->h_expr);
+ return AVERROR(EINVAL);
+ }
+
+ if ((vars_w[VAR_OUT_H] || vars_w[VAR_OH]) &&
+ (vars_h[VAR_OUT_W] || vars_h[VAR_OW])) {
+ av_log(ctx, AV_LOG_WARNING, "Circular references detected for width '%s' and height '%s' - possibly invalid.\n", scale->w_expr, scale->h_expr);
+ }
+
+ if (ctx->filter != &ff_vf_scale2ref &&
+ (vars_w[VAR_S2R_MAIN_W] || vars_h[VAR_S2R_MAIN_W] ||
+ vars_w[VAR_S2R_MAIN_H] || vars_h[VAR_S2R_MAIN_H] ||
+ vars_w[VAR_S2R_MAIN_A] || vars_h[VAR_S2R_MAIN_A] ||
+ vars_w[VAR_S2R_MAIN_SAR] || vars_h[VAR_S2R_MAIN_SAR] ||
+ vars_w[VAR_S2R_MAIN_DAR] || vars_h[VAR_S2R_MAIN_DAR] ||
+ vars_w[VAR_S2R_MDAR] || vars_h[VAR_S2R_MDAR] ||
+ vars_w[VAR_S2R_MAIN_HSUB] || vars_h[VAR_S2R_MAIN_HSUB] ||
+ vars_w[VAR_S2R_MAIN_VSUB] || vars_h[VAR_S2R_MAIN_VSUB] ||
+ vars_w[VAR_S2R_MAIN_N] || vars_h[VAR_S2R_MAIN_N] ||
+ vars_w[VAR_S2R_MAIN_T] || vars_h[VAR_S2R_MAIN_T] ||
+ vars_w[VAR_S2R_MAIN_POS] || vars_h[VAR_S2R_MAIN_POS]) ) {
+ av_log(ctx, AV_LOG_ERROR, "Expressions with scale2ref variables are not valid in scale filter.\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (scale->eval_mode == EVAL_MODE_INIT &&
+ (vars_w[VAR_N] || vars_h[VAR_N] ||
+ vars_w[VAR_T] || vars_h[VAR_T] ||
+ vars_w[VAR_POS] || vars_h[VAR_POS] ||
+ vars_w[VAR_S2R_MAIN_N] || vars_h[VAR_S2R_MAIN_N] ||
+ vars_w[VAR_S2R_MAIN_T] || vars_h[VAR_S2R_MAIN_T] ||
+ vars_w[VAR_S2R_MAIN_POS] || vars_h[VAR_S2R_MAIN_POS]) ) {
+ av_log(ctx, AV_LOG_ERROR, "Expressions with frame variables 'n', 't', 'pos' are not valid in init eval_mode.\n");
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+static int scale_parse_expr(AVFilterContext *ctx, char *str_expr, AVExpr **pexpr_ptr, const char *var, const char *args)
+{
+ ScaleContext *scale = ctx->priv;
+ int ret, is_inited = 0;
+ char *old_str_expr = NULL;
+ AVExpr *old_pexpr = NULL;
+
+ if (str_expr) {
+ old_str_expr = av_strdup(str_expr);
+ if (!old_str_expr)
+ return AVERROR(ENOMEM);
+ av_opt_set(scale, var, args, 0);
+ }
+
+ if (*pexpr_ptr) {
+ old_pexpr = *pexpr_ptr;
+ *pexpr_ptr = NULL;
+ is_inited = 1;
+ }
+
+ ret = av_expr_parse(pexpr_ptr, args, var_names,
+ NULL, NULL, NULL, NULL, 0, ctx);
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Cannot parse expression for %s: '%s'\n", var, args);
+ goto revert;
+ }
+
+ ret = check_exprs(ctx);
+ if (ret < 0)
+ goto revert;
+
+ if (is_inited && (ret = config_props(ctx->outputs[0])) < 0)
+ goto revert;
+
+ av_expr_free(old_pexpr);
+ old_pexpr = NULL;
+ av_freep(&old_str_expr);
+
+ return 0;
+
+revert:
+ av_expr_free(*pexpr_ptr);
+ *pexpr_ptr = NULL;
+ if (old_str_expr) {
+ av_opt_set(scale, var, old_str_expr, 0);
+ av_free(old_str_expr);
+ }
+ if (old_pexpr)
+ *pexpr_ptr = old_pexpr;
+
+ return ret;
+}
+