Browse code

avfilter/af_afade: improve accuracy and speed of gain computation

Gain computation for various curves was being done in a needlessly
inaccurate fashion. Of course these are all subjective curves, but when
a curve is advertised to the user, it should be matched as closely as
possible within the limitations of libm. In particular, the constants
kept here were pretty inaccurate for double precision.

Speed improvements are mainly due to the avoidance of pow, the most
notorious of the libm functions in terms of performance. To be fair, it
is the GNU libm that is among the worst, but it is not really GNU libm's fault
since others simply yield a higher error as measured in ULP.

"Magic" constants are also accordingly documented, since they take at
least a minute of thought for a casual reader.

Reviewed-by: Paul B Mahol <onemda@gmail.com>
Signed-off-by: Ganesh Ajjanagadde <gajjanagadde@gmail.com>

Ganesh Ajjanagadde authored on 2015/11/25 12:56:28
Showing 1 changed files
... ...
@@ -92,6 +92,7 @@ static int query_formats(AVFilterContext *ctx)
92 92
 
93 93
 static double fade_gain(int curve, int64_t index, int range)
94 94
 {
95
+#define CUBE(a) ((a)*(a)*(a))
95 96
     double gain;
96 97
 
97 98
     gain = av_clipd(1.0 * index / range, 0, 1.0);
... ...
@@ -101,22 +102,25 @@ static double fade_gain(int curve, int64_t index, int range)
101 101
         gain = sin(gain * M_PI / 2.0);
102 102
         break;
103 103
     case IQSIN:
104
-        gain = 0.636943 * asin(gain);
104
+        /* 0.6... = 2 / M_PI */
105
+        gain = 0.6366197723675814 * asin(gain);
105 106
         break;
106 107
     case ESIN:
107
-        gain = 1.0 - cos(M_PI / 4.0 * (pow(2.0*gain - 1, 3) + 1));
108
+        gain = 1.0 - cos(M_PI / 4.0 * (CUBE(2.0*gain - 1) + 1));
108 109
         break;
109 110
     case HSIN:
110 111
         gain = (1.0 - cos(gain * M_PI)) / 2.0;
111 112
         break;
112 113
     case IHSIN:
113
-        gain = 0.318471 * acos(1 - 2 * gain);
114
+        /* 0.3... = 1 / M_PI */
115
+        gain = 0.3183098861837907 * acos(1 - 2 * gain);
114 116
         break;
115 117
     case EXP:
116
-        gain = pow(0.1, (1 - gain) * 5.0);
118
+        /* -11.5... = 5*ln(0.1) */
119
+        gain = exp(-11.512925464970227 * (1 - gain));
117 120
         break;
118 121
     case LOG:
119
-        gain = av_clipd(0.0868589 * log(100000 * gain), 0, 1.0);
122
+        gain = av_clipd(1 + 0.2 * log10(gain), 0, 1.0);
120 123
         break;
121 124
     case PAR:
122 125
         gain = 1 - sqrt(1 - gain);
... ...
@@ -128,7 +132,7 @@ static double fade_gain(int curve, int64_t index, int range)
128 128
         gain *= gain;
129 129
         break;
130 130
     case CUB:
131
-        gain = gain * gain * gain;
131
+        gain = CUBE(gain);
132 132
         break;
133 133
     case SQU:
134 134
         gain = sqrt(gain);
... ...
@@ -137,10 +141,10 @@ static double fade_gain(int curve, int64_t index, int range)
137 137
         gain = cbrt(gain);
138 138
         break;
139 139
     case DESE:
140
-        gain = gain <= 0.5 ? pow(2 * gain, 1/3.) / 2: 1 - pow(2 * (1 - gain), 1/3.) / 2;
140
+        gain = gain <= 0.5 ? cbrt(2 * gain) / 2: 1 - cbrt(2 * (1 - gain)) / 2;
141 141
         break;
142 142
     case DESI:
143
-        gain = gain <= 0.5 ? pow(2 * gain, 3) / 2: 1 - pow(2 * (1 - gain), 3) / 2;
143
+        gain = gain <= 0.5 ? CUBE(2 * gain) / 2: 1 - CUBE(2 * (1 - gain)) / 2;
144 144
         break;
145 145
     }
146 146