this is based on stefanos work, especially all bugs are his fault ;) Originally committed as revision 23201 to svn://svn.ffmpeg.org/ffmpeg/trunktags/n0.8
@@ -30,6 +30,7 @@ | |||
#include "eval.h" | |||
typedef struct Parser{ | |||
const AVClass *class; | |||
int stack_index; | |||
char *s; | |||
const double *const_value; | |||
@@ -39,11 +40,14 @@ typedef struct Parser{ | |||
double (* const *func2)(void *, double a, double b); // NULL terminated | |||
const char * const *func2_name; // NULL terminated | |||
void *opaque; | |||
const char **error; | |||
int log_offset; | |||
void *log_ctx; | |||
#define VARS 10 | |||
double var[VARS]; | |||
} Parser; | |||
static const AVClass class = { "Eval", av_default_item_name, NULL, LIBAVUTIL_VERSION_INT, offsetof(Parser,log_offset), offsetof(Parser,log_ctx) }; | |||
static const int8_t si_prefixes['z' - 'E' + 1]={ | |||
['y'-'E']= -24, | |||
['z'-'E']= -21, | |||
@@ -201,7 +205,7 @@ static AVExpr * parse_primary(Parser *p) { | |||
p->s= strchr(p->s, '('); | |||
if(p->s==NULL){ | |||
*p->error = "undefined constant or missing ("; | |||
av_log(p, AV_LOG_ERROR, "undefined constant or missing (\n"); | |||
p->s= next; | |||
ff_free_expr(d); | |||
return NULL; | |||
@@ -211,7 +215,7 @@ static AVExpr * parse_primary(Parser *p) { | |||
av_freep(&d); | |||
d = parse_expr(p); | |||
if(p->s[0] != ')'){ | |||
*p->error = "missing )"; | |||
av_log(p, AV_LOG_ERROR, "missing )\n"); | |||
ff_free_expr(d); | |||
return NULL; | |||
} | |||
@@ -224,7 +228,7 @@ static AVExpr * parse_primary(Parser *p) { | |||
d->param[1] = parse_expr(p); | |||
} | |||
if(p->s[0] != ')'){ | |||
*p->error = "missing )"; | |||
av_log(p, AV_LOG_ERROR, "missing )\n"); | |||
ff_free_expr(d); | |||
return NULL; | |||
} | |||
@@ -273,7 +277,7 @@ static AVExpr * parse_primary(Parser *p) { | |||
} | |||
} | |||
*p->error = "unknown function"; | |||
av_log(p, AV_LOG_ERROR, "unknown function\n"); | |||
ff_free_expr(d); | |||
return NULL; | |||
} | |||
@@ -373,7 +377,8 @@ AVExpr *ff_parse_expr(const char *s, | |||
const char * const *const_name, | |||
const char * const *func1_name, double (* const *func1)(void *, double), | |||
const char * const *func2_name, double (* const *func2)(void *, double, double), | |||
const char **error){ | |||
int log_offset, void *log_ctx) | |||
{ | |||
Parser p; | |||
AVExpr *e = NULL; | |||
char *w = av_malloc(strlen(s) + 1); | |||
@@ -386,6 +391,7 @@ AVExpr *ff_parse_expr(const char *s, | |||
if (!isspace(*s++)) *wp++ = s[-1]; | |||
*wp++ = 0; | |||
p.class = &class; | |||
p.stack_index=100; | |||
p.s= w; | |||
p.const_name = const_name; | |||
@@ -393,7 +399,8 @@ AVExpr *ff_parse_expr(const char *s, | |||
p.func1_name = func1_name; | |||
p.func2 = func2; | |||
p.func2_name = func2_name; | |||
p.error= error; | |||
p.log_offset = log_offset; | |||
p.log_ctx = log_ctx; | |||
e = parse_expr(&p); | |||
if (!verify_expr(e)) { | |||
@@ -417,8 +424,9 @@ double ff_parse_and_eval_expr(const char *s, | |||
const char * const *const_name, const double *const_value, | |||
const char * const *func1_name, double (* const *func1)(void *, double), | |||
const char * const *func2_name, double (* const *func2)(void *, double, double), | |||
void *opaque, const char **error){ | |||
AVExpr *e = ff_parse_expr(s, const_name, func1_name, func1, func2_name, func2, error); | |||
void *opaque, int log_offset, void *log_ctx) | |||
{ | |||
AVExpr *e = ff_parse_expr(s, const_name, func1_name, func1, func2_name, func2, log_offset, log_ctx); | |||
double d; | |||
if (!e) return NAN; | |||
d = ff_eval_expr(e, const_value, opaque); | |||
@@ -440,12 +448,12 @@ static const char *const_names[]={ | |||
}; | |||
int main(void){ | |||
int i; | |||
printf("%f == 12.7\n", ff_parse_and_eval_expr("1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)", const_names, const_values, NULL, NULL, NULL, NULL, NULL, NULL)); | |||
printf("%f == 12.7\n", ff_parse_and_eval_expr("1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)", const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, NULL)); | |||
printf("%f == 0.931322575\n", ff_parse_and_eval_expr("80G/80Gi", const_names, const_values, NULL, NULL, NULL, NULL, NULL, NULL)); | |||
for(i=0; i<1050; i++){ | |||
START_TIMER | |||
ff_parse_and_eval_expr("1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)", const_names, const_values, NULL, NULL, NULL, NULL, NULL, NULL); | |||
ff_parse_and_eval_expr("1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)", const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, NULL); | |||
STOP_TIMER("ff_parse_and_eval_expr") | |||
} | |||
return 0; | |||
@@ -39,15 +39,15 @@ typedef struct AVExpr AVExpr; | |||
* @param func1 NULL terminated array of function pointers for functions which take 1 argument | |||
* @param func2_name NULL terminated array of zero terminated strings of func2 identifers | |||
* @param func2 NULL terminated array of function pointers for functions which take 2 arguments | |||
* @param error pointer to a char* which is set to an error message if something goes wrong | |||
* @param opaque a pointer which will be passed to all functions from func1 and func2 | |||
* @param log_ctx parent logging context | |||
* @return the value of the expression | |||
*/ | |||
double ff_parse_and_eval_expr(const char *s, | |||
const char * const *const_name, const double *const_value, | |||
const char * const *func1_name, double (* const *func1)(void *, double), | |||
const char * const *func2_name, double (* const *func2)(void *, double, double), | |||
void *opaque, const char **error); | |||
void *opaque, int log_offset, void *log_ctx); | |||
/** | |||
* Parses an expression. | |||
@@ -58,7 +58,7 @@ double ff_parse_and_eval_expr(const char *s, | |||
* @param func1 NULL terminated array of function pointers for functions which take 1 argument | |||
* @param func2_name NULL terminated array of zero terminated strings of func2 identifers | |||
* @param func2 NULL terminated array of function pointers for functions which take 2 arguments | |||
* @param error pointer to a char* which is set to an error message if something goes wrong | |||
* @param log_ctx parent logging context | |||
* @return AVExpr which must be freed with ff_free_expr() by the user when it is not needed anymore | |||
* NULL if anything went wrong | |||
*/ | |||
@@ -66,7 +66,7 @@ AVExpr *ff_parse_expr(const char *s, | |||
const char * const *const_name, | |||
const char * const *func1_name, double (* const *func1)(void *, double), | |||
const char * const *func2_name, double (* const *func2)(void *, double, double), | |||
const char **error); | |||
int log_offset, void *log_ctx); | |||
/** | |||
* Evaluates a previously parsed expression. | |||
@@ -147,7 +147,6 @@ int av_set_string3(void *obj, const char *name, const char *val, int alloc, cons | |||
char buf[256]; | |||
int cmd=0; | |||
double d; | |||
const char *error = NULL; | |||
if(*val == '+' || *val == '-') | |||
cmd= *(val++); | |||
@@ -156,8 +155,7 @@ int av_set_string3(void *obj, const char *name, const char *val, int alloc, cons | |||
buf[i]= val[i]; | |||
buf[i]=0; | |||
d = ff_parse_and_eval_expr(buf, const_names, const_values, NULL, NULL, NULL, NULL, NULL, &error); | |||
if(isnan(d)) { | |||
{ | |||
const AVOption *o_named= av_find_opt(obj, buf, o->unit, 0, 0); | |||
if(o_named && o_named->type == FF_OPT_TYPE_CONST) | |||
d= o_named->default_val; | |||
@@ -167,9 +165,11 @@ int av_set_string3(void *obj, const char *name, const char *val, int alloc, cons | |||
else if(!strcmp(buf, "none" )) d= 0; | |||
else if(!strcmp(buf, "all" )) d= ~0; | |||
else { | |||
if (error) | |||
av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\": %s\n", val, error); | |||
d = ff_parse_and_eval_expr(buf, const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, obj); | |||
if (isnan(d)){ | |||
av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\"\n", val); | |||
return AVERROR(EINVAL); | |||
} | |||
} | |||
} | |||
if(o->type == FF_OPT_TYPE_FLAGS){ | |||
@@ -67,7 +67,6 @@ int ff_rate_control_init(MpegEncContext *s) | |||
{ | |||
RateControlContext *rcc= &s->rc_context; | |||
int i; | |||
const char *error = NULL; | |||
static const char * const const_names[]={ | |||
"PI", | |||
"E", | |||
@@ -107,9 +106,9 @@ int ff_rate_control_init(MpegEncContext *s) | |||
}; | |||
emms_c(); | |||
rcc->rc_eq_eval = ff_parse_expr(s->avctx->rc_eq ? s->avctx->rc_eq : "tex^qComp", const_names, func1_names, func1, NULL, NULL, &error); | |||
rcc->rc_eq_eval = ff_parse_expr(s->avctx->rc_eq ? s->avctx->rc_eq : "tex^qComp", const_names, func1_names, func1, NULL, NULL, 0, s->avctx); | |||
if (!rcc->rc_eq_eval) { | |||
av_log(s->avctx, AV_LOG_ERROR, "Error parsing rc_eq \"%s\": %s\n", s->avctx->rc_eq, error? error : ""); | |||
av_log(s->avctx, AV_LOG_ERROR, "Error parsing rc_eq \"%s\"\n", s->avctx->rc_eq); | |||
return -1; | |||
} | |||