From patchwork Mon Dec 30 22:23:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marton Balint X-Patchwork-Id: 17076 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 1A083447DDB for ; Tue, 31 Dec 2019 00:24:03 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id E299B68ACE8; Tue, 31 Dec 2019 00:24:02 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from iq.passwd.hu (iq.passwd.hu [217.27.212.140]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id A0F2068ABD8 for ; Tue, 31 Dec 2019 00:23:56 +0200 (EET) Received: from localhost (localhost [127.0.0.1]) by iq.passwd.hu (Postfix) with ESMTP id C5024E397E; Mon, 30 Dec 2019 23:23:55 +0100 (CET) X-Virus-Scanned: amavisd-new at passwd.hu Received: from iq.passwd.hu ([127.0.0.1]) by localhost (iq.passwd.hu [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id NOQyrnmXEYpz; Mon, 30 Dec 2019 23:23:53 +0100 (CET) Received: from bluegene.passwd.hu (localhost [127.0.0.1]) by iq.passwd.hu (Postfix) with ESMTP id E0E79E3699; Mon, 30 Dec 2019 23:23:52 +0100 (CET) From: Marton Balint To: ffmpeg-devel@ffmpeg.org Date: Mon, 30 Dec 2019 23:23:40 +0100 Message-Id: <20191230222340.5832-1-cus@passwd.hu> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20191230194333.GV3089@michaelspb> References: <20191230194333.GV3089@michaelspb> Subject: [FFmpeg-devel] [PATCHv2 1/3] avutil/eval: separate AVExpr state to a new AVExprState struct X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Marton Balint MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Also add helper functions to allocate and free such a struct, and make it usable by providing a new av_eval_expr2 function for which you can specify a custom AVExprState. Signed-off-by: Marton Balint --- doc/APIchanges | 4 ++++ libavutil/eval.c | 36 +++++++++++++++++++++++++----------- libavutil/eval.h | 41 +++++++++++++++++++++++++++++++++++++++++ libavutil/version.h | 2 +- 4 files changed, 71 insertions(+), 12 deletions(-) diff --git a/doc/APIchanges b/doc/APIchanges index 3c24dc6fbc..d0b33bda02 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -15,6 +15,10 @@ libavutil: 2017-10-21 API changes, most recent first: +2020-01-xx - xxxxxxxxxx - lavu 56.39.100 - eval.h + Add AVExprState struct and av_expr_eval2, av_expr_state_alloc, + av_expr_state_free functions + 2019-12-27 - xxxxxxxxxx - lavu 56.38.100 - eval.h Add av_expr_count_func(). diff --git a/libavutil/eval.c b/libavutil/eval.c index d527f6a9d0..4619d0fba0 100644 --- a/libavutil/eval.c +++ b/libavutil/eval.c @@ -53,7 +53,6 @@ typedef struct Parser { void *opaque; int log_offset; void *log_ctx; -#define VARS 10 double *var; } Parser; @@ -173,7 +172,7 @@ struct AVExpr { double (*func2)(void *, double, double); } a; struct AVExpr *param[3]; - double *var; + AVExprState *state; }; static double etime(double v) @@ -191,7 +190,7 @@ static double eval_expr(Parser *p, AVExpr *e) case e_func2: return e->value * e->a.func2(p->opaque, eval_expr(p, e->param[0]), eval_expr(p, e->param[1])); case e_squish: return 1/(1+exp(4*eval_expr(p, e->param[0]))); case e_gauss: { double d = eval_expr(p, e->param[0]); return exp(-d*d/2)/sqrt(2*M_PI); } - case e_ld: return e->value * p->var[av_clip(eval_expr(p, e->param[0]), 0, VARS-1)]; + case e_ld: return e->value * p->var[av_clip(eval_expr(p, e->param[0]), 0, AV_EXPR_STATE_NB_VARS-1)]; case e_isnan: return e->value * !!isnan(eval_expr(p, e->param[0])); case e_isinf: return e->value * !!isinf(eval_expr(p, e->param[0])); case e_floor: return e->value * floor(eval_expr(p, e->param[0])); @@ -230,7 +229,7 @@ static double eval_expr(Parser *p, AVExpr *e) return x; } case e_random:{ - int idx= av_clip(eval_expr(p, e->param[0]), 0, VARS-1); + int idx= av_clip(eval_expr(p, e->param[0]), 0, AV_EXPR_STATE_NB_VARS-1); uint64_t r= isnan(p->var[idx]) ? 0 : p->var[idx]; r= r*1664525+1013904223; p->var[idx]= r; @@ -245,7 +244,7 @@ static double eval_expr(Parser *p, AVExpr *e) case e_taylor: { double t = 1, d = 0, v; double x = eval_expr(p, e->param[1]); - int id = e->param[2] ? av_clip(eval_expr(p, e->param[2]), 0, VARS-1) : 0; + int id = e->param[2] ? av_clip(eval_expr(p, e->param[2]), 0, AV_EXPR_STATE_NB_VARS-1) : 0; int i; double var0 = p->var[id]; for(i=0; i<1000; i++) { @@ -320,7 +319,7 @@ static double eval_expr(Parser *p, AVExpr *e) case e_div: return e->value * ((!CONFIG_FTRAPV || d2 ) ? (d / d2) : d * INFINITY); case e_add: return e->value * (d + d2); case e_last:return e->value * d2; - case e_st : return e->value * (p->var[av_clip(d, 0, VARS-1)]= d2); + case e_st : return e->value * (p->var[av_clip(d, 0, AV_EXPR_STATE_NB_VARS-1)]= d2); case e_hypot:return e->value * hypot(d, d2); case e_atan2:return e->value * atan2(d, d2); case e_bitand: return isnan(d) || isnan(d2) ? NAN : e->value * ((long int)d & (long int)d2); @@ -333,13 +332,23 @@ static double eval_expr(Parser *p, AVExpr *e) static int parse_expr(AVExpr **e, Parser *p); +AVExprState *av_expr_state_alloc(void) +{ + return av_mallocz(sizeof(AVExprState)); +} + +void av_expr_state_free(AVExprState **ps) +{ + av_freep(ps); +} + void av_expr_free(AVExpr *e) { if (!e) return; av_expr_free(e->param[0]); av_expr_free(e->param[1]); av_expr_free(e->param[2]); - av_freep(&e->var); + av_expr_state_free(&e->state); av_freep(&e); } @@ -724,8 +733,8 @@ int av_expr_parse(AVExpr **expr, const char *s, ret = AVERROR(EINVAL); goto end; } - e->var= av_mallocz(sizeof(double) *VARS); - if (!e->var) { + e->state = av_expr_state_alloc(); + if (!e->state) { ret = AVERROR(ENOMEM); goto end; } @@ -763,16 +772,21 @@ int av_expr_count_func(AVExpr *e, unsigned *counter, int size, int arg) return expr_count(e, counter, size, ((int[]){e_const, e_func1, e_func2})[arg]); } -double av_expr_eval(AVExpr *e, const double *const_values, void *opaque) +double av_expr_eval2(AVExpr *e, AVExprState *s, const double *const_values, void *opaque) { Parser p = { 0 }; - p.var= e->var; + p.var = s ? s->vars : e->state->vars; p.const_values = const_values; p.opaque = opaque; return eval_expr(&p, e); } +double av_expr_eval(AVExpr *e, const double *const_values, void *opaque) +{ + return av_expr_eval2(e, NULL, const_values, opaque); +} + int av_expr_parse_and_eval(double *d, const char *s, const char * const *const_names, const double *const_values, const char * const *func1_names, double (* const *funcs1)(void *, double), diff --git a/libavutil/eval.h b/libavutil/eval.h index 068c62cdab..d5b34e54e8 100644 --- a/libavutil/eval.h +++ b/libavutil/eval.h @@ -30,6 +30,21 @@ typedef struct AVExpr AVExpr; +/** + * This structure stores a state used by the expression evaluator. + * It must be allocated and freed with its proper allocation functions. + * + * @see av_expr_state_alloc() + * @see av_expr_state_free() + */ +typedef struct AVExprState { +#define AV_EXPR_STATE_NB_VARS 10 + /* + * Internal variables used by stateful functions like lt(), st() and rand(). + */ + double vars[AV_EXPR_STATE_NB_VARS]; +} AVExprState; + /** * Parse and evaluate an expression. * Note, this is significantly slower than av_expr_eval(). @@ -86,6 +101,22 @@ int av_expr_parse(AVExpr **expr, const char *s, */ double av_expr_eval(AVExpr *e, const double *const_values, void *opaque); +/** + * Evaluate a previously parsed expression using a custom state. + * + * Some expressions can use stateful functions, like random(), st() and ld(). + * With this function you can provide your own state to the evaluator instead + * of using the internal state of the AVExpr. This makes it possible to use the + * same AVExpr in multiple threads each with their own AVExprState avoiding + * unprotected concurrent access of the internal AVExpr state. + * + * @param s the state of the expression, if NULL, the internal state of AVExpr will be used + * @param const_values a zero terminated array of values for the identifiers from av_expr_parse() const_names + * @param opaque a pointer which will be passed to all functions from funcs1 and funcs2 + * @return the value of the expression + */ +double av_expr_eval2(AVExpr *e, AVExprState *s, const double *const_values, void *opaque); + /** * Track the presence of variables and their number of occurrences in a parsed expression * @@ -134,4 +165,14 @@ void av_expr_free(AVExpr *e); */ double av_strtod(const char *numstr, char **tail); +/** + * Allocate a new AVExprState struct + */ +AVExprState *av_expr_state_alloc(void); + +/** + * Free an allocated AVExprState struct and set its pointer to NULL + */ +void av_expr_state_free(AVExprState **ps); + #endif /* AVUTIL_EVAL_H */ diff --git a/libavutil/version.h b/libavutil/version.h index af8f614aff..2bc1b98615 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -79,7 +79,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 56 -#define LIBAVUTIL_VERSION_MINOR 38 +#define LIBAVUTIL_VERSION_MINOR 39 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \