From ce2cfa67aa26e70717eb8b184f232b9c41b81001 Mon Sep 17 00:00:00 2001 From: Gyan Doshi Date: Tue, 31 Dec 2019 17:15:01 +0530 Subject: avfilter/scale: add function to check expressions Allows finer identification and logging of invalid expressions and use of a single list for symbols and their index for both scale and scale2ref. --- libavfilter/vf_scale.c | 113 +++++++++++++++++++++++++++++-------------------- 1 file changed, 67 insertions(+), 46 deletions(-) (limited to 'libavfilter/vf_scale.c') diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c index 64f5eb0642..7f5cc6ce75 100644 --- a/libavfilter/vf_scale.c +++ b/libavfilter/vf_scale.c @@ -54,6 +54,13 @@ static const char *const var_names[] = { "vsub", "ohsub", "ovsub", + "main_w", + "main_h", + "main_a", + "main_sar", + "main_dar", "mdar", + "main_hsub", + "main_vsub", NULL }; @@ -69,39 +76,6 @@ enum var_name { VAR_VSUB, VAR_OHSUB, VAR_OVSUB, - VARS_NB -}; - -/** - * This must be kept in sync with var_names so that it is always a - * complete list of var_names with the scale2ref specific names - * appended. scale2ref values must appear in the order they appear - * in the var_name_scale2ref enum but also be below all of the - * non-scale2ref specific values. - */ -static const char *const var_names_scale2ref[] = { - "in_w", "iw", - "in_h", "ih", - "out_w", "ow", - "out_h", "oh", - "a", - "sar", - "dar", - "hsub", - "vsub", - "ohsub", - "ovsub", - "main_w", - "main_h", - "main_a", - "main_sar", - "main_dar", "mdar", - "main_hsub", - "main_vsub", - NULL -}; - -enum var_name_scale2ref { VAR_S2R_MAIN_W, VAR_S2R_MAIN_H, VAR_S2R_MAIN_A, @@ -109,7 +83,7 @@ enum var_name_scale2ref { VAR_S2R_MAIN_DAR, VAR_S2R_MDAR, VAR_S2R_MAIN_HSUB, VAR_S2R_MAIN_VSUB, - VARS_S2R_NB + VARS_NB }; enum EvalMode { @@ -145,7 +119,7 @@ typedef struct ScaleContext { char *h_expr; ///< height expression string AVExpr *w_pexpr; AVExpr *h_pexpr; - double var_values[VARS_NB + VARS_S2R_NB]; + double var_values[VARS_NB]; char *flags_str; @@ -173,14 +147,57 @@ AVFilter ff_vf_scale2ref; 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_ERROR, "Circular expressions invalid for width '%s' and height '%s'.\n", scale->w_expr, scale->h_expr); + return AVERROR(EINVAL); + } + + 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]) ) { + av_log(ctx, AV_LOG_ERROR, "Expressions with scale2ref variables are not valid in scale filter.\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; - const char scale2ref = ctx->filter == &ff_vf_scale2ref; - const char *const *names = scale2ref ? var_names_scale2ref : var_names; if (str_expr) { old_str_expr = av_strdup(str_expr); @@ -195,13 +212,17 @@ static int scale_parse_expr(AVFilterContext *ctx, char *str_expr, AVExpr **pexpr is_inited = 1; } - ret = av_expr_parse(pexpr_ptr, args, names, + 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; @@ -391,15 +412,15 @@ static int scale_eval_dimensions(AVFilterContext *ctx) scale->var_values[VAR_OVSUB] = 1 << out_desc->log2_chroma_h; if (scale2ref) { - scale->var_values[VARS_NB + VAR_S2R_MAIN_W] = main_link->w; - scale->var_values[VARS_NB + VAR_S2R_MAIN_H] = main_link->h; - scale->var_values[VARS_NB + VAR_S2R_MAIN_A] = (double) main_link->w / main_link->h; - scale->var_values[VARS_NB + VAR_S2R_MAIN_SAR] = main_link->sample_aspect_ratio.num ? + scale->var_values[VAR_S2R_MAIN_W] = main_link->w; + scale->var_values[VAR_S2R_MAIN_H] = main_link->h; + scale->var_values[VAR_S2R_MAIN_A] = (double) main_link->w / main_link->h; + scale->var_values[VAR_S2R_MAIN_SAR] = main_link->sample_aspect_ratio.num ? (double) main_link->sample_aspect_ratio.num / main_link->sample_aspect_ratio.den : 1; - scale->var_values[VARS_NB + VAR_S2R_MAIN_DAR] = scale->var_values[VARS_NB + VAR_S2R_MDAR] = - scale->var_values[VARS_NB + VAR_S2R_MAIN_A] * scale->var_values[VARS_NB + VAR_S2R_MAIN_SAR]; - scale->var_values[VARS_NB + VAR_S2R_MAIN_HSUB] = 1 << main_desc->log2_chroma_w; - scale->var_values[VARS_NB + VAR_S2R_MAIN_VSUB] = 1 << main_desc->log2_chroma_h; + scale->var_values[VAR_S2R_MAIN_DAR] = scale->var_values[VAR_S2R_MDAR] = + scale->var_values[VAR_S2R_MAIN_A] * scale->var_values[VAR_S2R_MAIN_SAR]; + scale->var_values[VAR_S2R_MAIN_HSUB] = 1 << main_desc->log2_chroma_w; + scale->var_values[VAR_S2R_MAIN_VSUB] = 1 << main_desc->log2_chroma_h; } res = av_expr_eval(scale->w_pexpr, scale->var_values, NULL); -- cgit v1.2.3