Mercurial > libavcodec.hg
annotate eval.c @ 1757:3906ddbaffec libavcodec
optimization & bugfix extracted from the 4k line diff between ffmpeg 0.4.7 and http://www.alicestreet.com/ffh263.html
the other parts of the diff where
1. spelling fixes (rejected as only a small part of it could be applied automatically)
2. cosmetics (reindention, function reordering, var renaming, ...) with bugs (rejected)
3. rtp related stuff (rejetced as it breaks several codecs)
4. some changes to the intra/inter decission & scene change detection (quality tests needed first)
| author | michael |
|---|---|
| date | Sat, 24 Jan 2004 23:47:33 +0000 |
| parents | 932d306bf1dc |
| children | 2152760d08ad |
| 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); | |
| 118 p->s++; // ")" or "," | |
| 119 if(p->s[-1]== ','){ | |
| 120 evalExpression(p); | |
| 121 d2= pop(p); | |
| 122 p->s++; // ")" | |
| 123 } | |
| 124 | |
| 125 if( strmatch(next, "sinh" ) ) d= sinh(d); | |
| 126 else if( strmatch(next, "cosh" ) ) d= cosh(d); | |
| 127 else if( strmatch(next, "tanh" ) ) d= tanh(d); | |
| 128 else if( strmatch(next, "sin" ) ) d= sin(d); | |
| 129 else if( strmatch(next, "cos" ) ) d= cos(d); | |
| 130 else if( strmatch(next, "tan" ) ) d= tan(d); | |
| 131 else if( strmatch(next, "exp" ) ) d= exp(d); | |
| 132 else if( strmatch(next, "log" ) ) d= log(d); | |
| 133 else if( strmatch(next, "squish") ) d= 1/(1+exp(4*d)); | |
| 134 else if( strmatch(next, "gauss" ) ) d= exp(-d*d/2)/sqrt(2*M_PI); | |
| 1057 | 135 else if( strmatch(next, "abs" ) ) d= fabs(d); |
| 612 | 136 else if( strmatch(next, "max" ) ) d= d > d2 ? d : d2; |
| 137 else if( strmatch(next, "min" ) ) d= d < d2 ? d : d2; | |
| 138 else if( strmatch(next, "gt" ) ) d= d > d2 ? 1.0 : 0.0; | |
| 139 else if( strmatch(next, "lt" ) ) d= d > d2 ? 0.0 : 1.0; | |
| 140 else if( strmatch(next, "eq" ) ) d= d == d2 ? 1.0 : 0.0; | |
| 141 // else if( strmatch(next, "l1" ) ) d= 1 + d2*(d - 1); | |
| 142 // else if( strmatch(next, "sq01" ) ) d= (d >= 0.0 && d <=1.0) ? 1.0 : 0.0; | |
| 143 else{ | |
| 144 int error=1; | |
| 145 for(i=0; p->func1_name && p->func1_name[i]; i++){ | |
| 146 if(strmatch(next, p->func1_name[i])){ | |
| 147 d= p->func1[i](p->opaque, d); | |
| 148 error=0; | |
| 149 break; | |
| 150 } | |
| 151 } | |
| 152 | |
| 153 for(i=0; p->func2_name && p->func2_name[i]; i++){ | |
| 154 if(strmatch(next, p->func2_name[i])){ | |
| 155 d= p->func2[i](p->opaque, d, d2); | |
| 156 error=0; | |
| 157 break; | |
| 158 } | |
| 159 } | |
| 160 | |
| 161 if(error){ | |
|
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1106
diff
changeset
|
162 av_log(NULL, AV_LOG_ERROR, "Parser: unknown function in \"%s\"\n", next); |
| 612 | 163 return; |
| 164 } | |
| 165 } | |
| 166 | |
| 167 if(p->s[-1]!= ')'){ | |
|
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: missing ) in \"%s\"\n", next); |
| 612 | 169 return; |
| 170 } | |
| 171 push(p, d); | |
| 172 } | |
| 173 | |
| 174 static void evalPow(Parser *p){ | |
| 175 int neg= 0; | |
| 176 if(p->s[0]=='+') p->s++; | |
| 177 | |
| 178 if(p->s[0]=='-'){ | |
| 179 neg= 1; | |
| 180 p->s++; | |
| 181 } | |
| 182 | |
| 183 if(p->s[0]=='('){ | |
| 184 p->s++;; | |
| 185 evalExpression(p); | |
| 186 | |
| 187 if(p->s[0]!=')') | |
|
1598
932d306bf1dc
av_log() patch by (Michel Bardiaux <mbardiaux at peaktime dot be>)
michael
parents:
1106
diff
changeset
|
188 av_log(NULL, AV_LOG_ERROR, "Parser: missing )\n"); |
| 612 | 189 p->s++; |
| 190 }else{ | |
| 191 evalPrimary(p); | |
| 192 } | |
| 193 | |
| 194 if(neg) push(p, -pop(p)); | |
| 195 } | |
| 196 | |
| 197 static void evalFactor(Parser *p){ | |
| 198 evalPow(p); | |
| 199 while(p->s[0]=='^'){ | |
| 200 double d; | |
| 201 | |
| 202 p->s++; | |
| 203 evalPow(p); | |
| 204 d= pop(p); | |
| 205 push(p, pow(pop(p), d)); | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 static void evalTerm(Parser *p){ | |
| 210 evalFactor(p); | |
| 211 while(p->s[0]=='*' || p->s[0]=='/'){ | |
| 212 int inv= p->s[0]=='/'; | |
| 213 double d; | |
| 214 | |
| 215 p->s++; | |
| 216 evalFactor(p); | |
| 217 d= pop(p); | |
| 218 if(inv) d= 1.0/d; | |
| 219 push(p, d * pop(p)); | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 static void evalExpression(Parser *p){ | |
| 224 evalTerm(p); | |
| 225 while(p->s[0]=='+' || p->s[0]=='-'){ | |
| 226 int sign= p->s[0]=='-'; | |
| 227 double d; | |
| 228 | |
| 229 p->s++; | |
| 230 evalTerm(p); | |
| 231 d= pop(p); | |
| 232 if(sign) d= -d; | |
| 233 push(p, d + pop(p)); | |
| 234 } | |
| 235 } | |
| 236 | |
| 1057 | 237 double ff_eval(char *s, double *const_value, const char **const_name, |
| 238 double (**func1)(void *, double), const char **func1_name, | |
| 612 | 239 double (**func2)(void *, double, double), char **func2_name, |
| 240 void *opaque){ | |
| 241 Parser p; | |
| 242 | |
| 243 p.stack_index=0; | |
| 244 p.s= s; | |
| 245 p.const_value= const_value; | |
| 246 p.const_name = const_name; | |
| 247 p.func1 = func1; | |
| 248 p.func1_name = func1_name; | |
| 249 p.func2 = func2; | |
| 250 p.func2_name = func2_name; | |
| 251 p.opaque = opaque; | |
| 252 | |
| 253 evalExpression(&p); | |
| 254 return pop(&p); | |
| 255 } |
