Mercurial > libavcodec.hg
annotate eval.c @ 2071:41d30bae5019 libavcodec
attempt to create some separation in the FLAC system with respect to
demuxer and decoder layers by enabling the FLAC decoder to decode data
without needing the entire file, from start to finish
| author | melanson |
|---|---|
| date | Thu, 10 Jun 2004 04:13:43 +0000 |
| parents | 2152760d08ad |
| children | 0934621b6453 |
| rev | line source |
|---|---|
| 612 | 1 /* |
| 2 * simple arithmetic expression evaluator | |
| 3 * | |
| 4 * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at> | |
| 5 * | |
| 6 * This library is free software; you can redistribute it and/or | |
| 7 * modify it under the terms of the GNU Lesser General Public | |
| 8 * License as published by the Free Software Foundation; either | |
| 9 * version 2 of the License, or (at your option) any later version. | |
| 10 * | |
| 11 * This library is distributed in the hope that it will be useful, | |
| 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 * Lesser General Public License for more details. | |
| 15 * | |
| 16 * You should have received a copy of the GNU Lesser General Public | |
| 17 * License along with this library; if not, write to the Free Software | |
| 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 19 * | |
| 20 */ | |
| 21 | |
| 1106 | 22 /** |
| 23 * @file eval.c | |
| 24 * simple arithmetic expression evaluator. | |
| 25 * | |
| 612 | 26 * see http://joe.hotchkiss.com/programming/eval/eval.html |
| 27 */ | |
| 28 | |
| 1057 | 29 #include "avcodec.h" |
| 30 #include "mpegvideo.h" | |
| 31 | |
| 612 | 32 #include <stdio.h> |
| 33 #include <stdlib.h> | |
| 34 #include <string.h> | |
| 35 #include <math.h> | |
| 36 | |
|
614
b786f15df503
NAN doesnt exist on FreeBSD patch by (R?mi Guyomarch <rguyom at pobox dot com>)
michaelni
parents:
612
diff
changeset
|
37 #ifndef NAN |
|
b786f15df503
NAN doesnt exist on FreeBSD patch by (R?mi Guyomarch <rguyom at pobox dot com>)
michaelni
parents:
612
diff
changeset
|
38 #define NAN 0 |
|
b786f15df503
NAN doesnt exist on FreeBSD patch by (R?mi Guyomarch <rguyom at pobox dot com>)
michaelni
parents:
612
diff
changeset
|
39 #endif |
|
b786f15df503
NAN doesnt exist on FreeBSD patch by (R?mi Guyomarch <rguyom at pobox dot com>)
michaelni
parents:
612
diff
changeset
|
40 |
| 627 | 41 #ifndef M_PI |
| 42 #define M_PI 3.14159265358979323846 | |
| 43 #endif | |
| 44 | |
| 612 | 45 #define STACK_SIZE 100 |
| 46 | |
| 47 typedef struct Parser{ | |
| 48 double stack[STACK_SIZE]; | |
| 49 int stack_index; | |
| 50 char *s; | |
| 51 double *const_value; | |
| 1057 | 52 const char **const_name; // NULL terminated |
| 612 | 53 double (**func1)(void *, double a); // NULL terminated |
| 1057 | 54 const char **func1_name; // NULL terminated |
| 612 | 55 double (**func2)(void *, double a, double b); // NULL terminated |
| 56 char **func2_name; // NULL terminated | |
| 57 void *opaque; | |
| 58 } Parser; | |
| 59 | |
| 60 static void evalExpression(Parser *p); | |
| 61 | |
| 62 static void push(Parser *p, double d){ | |
| 63 if(p->stack_index+1>= STACK_SIZE){ | |
|
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1106
diff
changeset
|
64 av_log(NULL, AV_LOG_ERROR, "stack overflow in the parser\n"); |
| 612 | 65 return; |
| 66 } | |
| 67 p->stack[ p->stack_index++ ]= d; | |
| 68 //printf("push %f\n", d); fflush(stdout); | |
| 69 } | |
| 70 | |
| 71 static double pop(Parser *p){ | |
| 72 if(p->stack_index<=0){ | |
|
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1106
diff
changeset
|
73 av_log(NULL, AV_LOG_ERROR, "stack underflow in the parser\n"); |
| 612 | 74 return NAN; |
| 75 } | |
| 76 //printf("pop\n"); fflush(stdout); | |
| 77 return p->stack[ --p->stack_index ]; | |
| 78 } | |
| 79 | |
| 1057 | 80 static int strmatch(const char *s, const char *prefix){ |
| 612 | 81 int i; |
| 82 for(i=0; prefix[i]; i++){ | |
| 83 if(prefix[i] != s[i]) return 0; | |
| 84 } | |
| 85 return 1; | |
| 86 } | |
| 87 | |
| 88 static void evalPrimary(Parser *p){ | |
| 89 double d, d2=NAN; | |
| 90 char *next= p->s; | |
| 91 int i; | |
| 92 | |
| 93 /* number */ | |
| 94 d= strtod(p->s, &next); | |
| 95 if(next != p->s){ | |
| 96 push(p, d); | |
| 97 p->s= next; | |
| 98 return; | |
| 99 } | |
| 100 | |
| 101 /* named constants */ | |
| 102 for(i=0; p->const_name[i]; i++){ | |
| 103 if(strmatch(p->s, p->const_name[i])){ | |
| 104 push(p, p->const_value[i]); | |
| 105 p->s+= strlen(p->const_name[i]); | |
| 106 return; | |
| 107 } | |
| 108 } | |
| 109 | |
| 110 p->s= strchr(p->s, '('); | |
| 111 if(p->s==NULL){ | |
|
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1106
diff
changeset
|
112 av_log(NULL, AV_LOG_ERROR, "Parser: missing ( in \"%s\"\n", next); |
| 612 | 113 return; |
| 114 } | |
| 115 p->s++; // "(" | |
| 116 evalExpression(p); | |
| 117 d= pop(p); | |
| 1815 | 118 if(p->s[0]== ','){ |
| 119 p->s++; // "," | |
| 612 | 120 evalExpression(p); |
| 121 d2= pop(p); | |
| 122 } | |
| 1815 | 123 if(p->s[0] != ')'){ |
| 124 av_log(NULL, AV_LOG_ERROR, "Parser: missing ) in \"%s\"\n", next); | |
| 125 return; | |
| 126 } | |
| 127 p->s++; // ")" | |
| 612 | 128 |
| 129 if( strmatch(next, "sinh" ) ) d= sinh(d); | |
| 130 else if( strmatch(next, "cosh" ) ) d= cosh(d); | |
| 131 else if( strmatch(next, "tanh" ) ) d= tanh(d); | |
| 132 else if( strmatch(next, "sin" ) ) d= sin(d); | |
| 133 else if( strmatch(next, "cos" ) ) d= cos(d); | |
| 134 else if( strmatch(next, "tan" ) ) d= tan(d); | |
| 135 else if( strmatch(next, "exp" ) ) d= exp(d); | |
| 136 else if( strmatch(next, "log" ) ) d= log(d); | |
| 137 else if( strmatch(next, "squish") ) d= 1/(1+exp(4*d)); | |
| 138 else if( strmatch(next, "gauss" ) ) d= exp(-d*d/2)/sqrt(2*M_PI); | |
| 1057 | 139 else if( strmatch(next, "abs" ) ) d= fabs(d); |
| 612 | 140 else if( strmatch(next, "max" ) ) d= d > d2 ? d : d2; |
| 141 else if( strmatch(next, "min" ) ) d= d < d2 ? d : d2; | |
| 142 else if( strmatch(next, "gt" ) ) d= d > d2 ? 1.0 : 0.0; | |
| 1815 | 143 else if( strmatch(next, "gte" ) ) d= d >= d2 ? 1.0 : 0.0; |
| 612 | 144 else if( strmatch(next, "lt" ) ) d= d > d2 ? 0.0 : 1.0; |
| 1815 | 145 else if( strmatch(next, "lte" ) ) d= d >= d2 ? 0.0 : 1.0; |
| 612 | 146 else if( strmatch(next, "eq" ) ) d= d == d2 ? 1.0 : 0.0; |
| 147 // else if( strmatch(next, "l1" ) ) d= 1 + d2*(d - 1); | |
| 148 // else if( strmatch(next, "sq01" ) ) d= (d >= 0.0 && d <=1.0) ? 1.0 : 0.0; | |
| 149 else{ | |
| 150 int error=1; | |
| 151 for(i=0; p->func1_name && p->func1_name[i]; i++){ | |
| 152 if(strmatch(next, p->func1_name[i])){ | |
| 153 d= p->func1[i](p->opaque, d); | |
| 154 error=0; | |
| 155 break; | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 for(i=0; p->func2_name && p->func2_name[i]; i++){ | |
| 160 if(strmatch(next, p->func2_name[i])){ | |
| 161 d= p->func2[i](p->opaque, d, d2); | |
| 162 error=0; | |
| 163 break; | |
| 164 } | |
| 165 } | |
| 166 | |
| 167 if(error){ | |
|
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1106
diff
changeset
|
168 av_log(NULL, AV_LOG_ERROR, "Parser: unknown function in \"%s\"\n", next); |
| 612 | 169 return; |
| 170 } | |
| 171 } | |
| 172 | |
| 173 push(p, d); | |
| 174 } | |
| 175 | |
| 176 static void evalPow(Parser *p){ | |
| 177 int neg= 0; | |
| 178 if(p->s[0]=='+') p->s++; | |
| 179 | |
| 180 if(p->s[0]=='-'){ | |
| 181 neg= 1; | |
| 182 p->s++; | |
| 183 } | |
| 184 | |
| 185 if(p->s[0]=='('){ | |
| 186 p->s++;; | |
| 187 evalExpression(p); | |
| 188 | |
| 189 if(p->s[0]!=')') | |
|
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1106
diff
changeset
|
190 av_log(NULL, AV_LOG_ERROR, "Parser: missing )\n"); |
| 612 | 191 p->s++; |
| 192 }else{ | |
| 193 evalPrimary(p); | |
| 194 } | |
| 195 | |
| 196 if(neg) push(p, -pop(p)); | |
| 197 } | |
| 198 | |
| 199 static void evalFactor(Parser *p){ | |
| 200 evalPow(p); | |
| 201 while(p->s[0]=='^'){ | |
| 202 double d; | |
| 203 | |
| 204 p->s++; | |
| 205 evalPow(p); | |
| 206 d= pop(p); | |
| 207 push(p, pow(pop(p), d)); | |
| 208 } | |
| 209 } | |
| 210 | |
| 211 static void evalTerm(Parser *p){ | |
| 212 evalFactor(p); | |
| 213 while(p->s[0]=='*' || p->s[0]=='/'){ | |
| 214 int inv= p->s[0]=='/'; | |
| 215 double d; | |
| 216 | |
| 217 p->s++; | |
| 218 evalFactor(p); | |
| 219 d= pop(p); | |
| 220 if(inv) d= 1.0/d; | |
| 221 push(p, d * pop(p)); | |
| 222 } | |
| 223 } | |
| 224 | |
| 225 static void evalExpression(Parser *p){ | |
| 226 evalTerm(p); | |
| 227 while(p->s[0]=='+' || p->s[0]=='-'){ | |
| 228 int sign= p->s[0]=='-'; | |
| 229 double d; | |
| 230 | |
| 231 p->s++; | |
| 232 evalTerm(p); | |
| 233 d= pop(p); | |
| 234 if(sign) d= -d; | |
| 235 push(p, d + pop(p)); | |
| 236 } | |
| 237 } | |
| 238 | |
| 1057 | 239 double ff_eval(char *s, double *const_value, const char **const_name, |
| 240 double (**func1)(void *, double), const char **func1_name, | |
| 612 | 241 double (**func2)(void *, double, double), char **func2_name, |
| 242 void *opaque){ | |
| 243 Parser p; | |
| 244 | |
| 245 p.stack_index=0; | |
| 246 p.s= s; | |
| 247 p.const_value= const_value; | |
| 248 p.const_name = const_name; | |
| 249 p.func1 = func1; | |
| 250 p.func1_name = func1_name; | |
| 251 p.func2 = func2; | |
| 252 p.func2_name = func2_name; | |
| 253 p.opaque = opaque; | |
| 254 | |
| 255 evalExpression(&p); | |
| 256 return pop(&p); | |
| 257 } |
