Browse code

lavfi/curves: do not automatically insert points at x=0 and x=1

There is actually a need for the origin and end point not to be defined.
We can not automatically insert them with the y value of the first and
last point as it will influence the curves in a wrong way.

Fixes #5397

Clément Bœsch authored on 2016/07/16 20:46:32
Showing 3 changed files
... ...
@@ -7,6 +7,7 @@ version <next>:
7 7
 - Changed metadata print option to accept general urls
8 8
 - Alias muxer for Ogg Video (.ogv)
9 9
 - VP8 in Ogg muxing
10
+- curves filter doesn't automatically insert points at x=0 and x=1 anymore
10 11
 
11 12
 
12 13
 version 3.1:
... ...
@@ -5710,10 +5710,6 @@ strictly increasing over the x-axis, and their @var{x} and @var{y} values must
5710 5710
 be in the @var{[0;1]} interval.  If the computed curves happened to go outside
5711 5711
 the vector spaces, the values will be clipped accordingly.
5712 5712
 
5713
-If there is no key point defined in @code{x=0}, the filter will automatically
5714
-insert a @var{(0;0)} point. In the same way, if there is no key point defined
5715
-in @code{x=1}, the filter will automatically insert a @var{(1;1)} point.
5716
-
5717 5713
 The filter accepts the following options:
5718 5714
 
5719 5715
 @table @option
... ...
@@ -5765,13 +5761,13 @@ defined using the following syntax: @code{x0/y0 x1/y1 x2/y2 ...}.
5765 5765
 @item
5766 5766
 Increase slightly the middle level of blue:
5767 5767
 @example
5768
-curves=blue='0.5/0.58'
5768
+curves=blue='0/0 0.5/0.58 1/1'
5769 5769
 @end example
5770 5770
 
5771 5771
 @item
5772 5772
 Vintage effect:
5773 5773
 @example
5774
-curves=r='0/0.11 .42/.51 1/0.95':g='0.50/0.48':b='0/0.22 .49/.44 1/0.8'
5774
+curves=r='0/0.11 .42/.51 1/0.95':g='0/0 0.50/0.48 1/1':b='0/0.22 .49/.44 1/0.8'
5775 5775
 @end example
5776 5776
 Here we obtain the following coordinates for each components:
5777 5777
 @table @var
... ...
@@ -5798,7 +5794,7 @@ curves=vintage
5798 5798
 @item
5799 5799
 Use a Photoshop preset and redefine the points of the green component:
5800 5800
 @example
5801
-curves=psfile='MyCurvesPresets/purple.acv':green='0.45/0.53'
5801
+curves=psfile='MyCurvesPresets/purple.acv':green='0/0 0.45/0.53 1/1'
5802 5802
 @end example
5803 5803
 @end itemize
5804 5804
 
... ...
@@ -110,25 +110,25 @@ static const struct {
110 110
     const char *master;
111 111
 } curves_presets[] = {
112 112
     [PRESET_COLOR_NEGATIVE] = {
113
-        "0/1 0.129/1 0.466/0.498 0.725/0 1/0",
114
-        "0/1 0.109/1 0.301/0.498 0.517/0 1/0",
115
-        "0/1 0.098/1 0.235/0.498 0.423/0 1/0",
113
+        "0.129/1 0.466/0.498 0.725/0",
114
+        "0.109/1 0.301/0.498 0.517/0",
115
+        "0.098/1 0.235/0.498 0.423/0",
116 116
     },
117 117
     [PRESET_CROSS_PROCESS] = {
118
-        "0.25/0.156 0.501/0.501 0.686/0.745",
119
-        "0.25/0.188 0.38/0.501 0.745/0.815 1/0.815",
120
-        "0.231/0.094 0.709/0.874",
118
+        "0/0 0.25/0.156 0.501/0.501 0.686/0.745 1/1",
119
+        "0/0 0.25/0.188 0.38/0.501 0.745/0.815 1/0.815",
120
+        "0/0 0.231/0.094 0.709/0.874 1/1",
121 121
     },
122
-    [PRESET_DARKER]             = { .master = "0.5/0.4" },
123
-    [PRESET_INCREASE_CONTRAST]  = { .master = "0.149/0.066 0.831/0.905 0.905/0.98" },
124
-    [PRESET_LIGHTER]            = { .master = "0.4/0.5" },
125
-    [PRESET_LINEAR_CONTRAST]    = { .master = "0.305/0.286 0.694/0.713" },
126
-    [PRESET_MEDIUM_CONTRAST]    = { .master = "0.286/0.219 0.639/0.643" },
122
+    [PRESET_DARKER]             = { .master = "0/0 0.5/0.4 1/1" },
123
+    [PRESET_INCREASE_CONTRAST]  = { .master = "0/0 0.149/0.066 0.831/0.905 0.905/0.98 1/1" },
124
+    [PRESET_LIGHTER]            = { .master = "0/0 0.4/0.5 1/1" },
125
+    [PRESET_LINEAR_CONTRAST]    = { .master = "0/0 0.305/0.286 0.694/0.713 1/1" },
126
+    [PRESET_MEDIUM_CONTRAST]    = { .master = "0/0 0.286/0.219 0.639/0.643 1/1" },
127 127
     [PRESET_NEGATIVE]           = { .master = "0/1 1/0" },
128
-    [PRESET_STRONG_CONTRAST]    = { .master = "0.301/0.196 0.592/0.6 0.686/0.737" },
128
+    [PRESET_STRONG_CONTRAST]    = { .master = "0/0 0.301/0.196 0.592/0.6 0.686/0.737 1/1" },
129 129
     [PRESET_VINTAGE] = {
130 130
         "0/0.11 0.42/0.51 1/0.95",
131
-        "0.50/0.48",
131
+        "0/0 0.50/0.48 1/1",
132 132
         "0/0.22 0.49/0.44 1/0.8",
133 133
     }
134 134
 };
... ...
@@ -177,28 +177,11 @@ static int parse_points_str(AVFilterContext *ctx, struct keypoint **points, cons
177 177
         last = point;
178 178
     }
179 179
 
180
-    /* auto insert first key point if missing at x=0 */
181
-    if (!*points) {
182
-        last = make_point(0, 0, NULL);
183
-        if (!last)
184
-            return AVERROR(ENOMEM);
185
-        last->x = last->y = 0;
186
-        *points = last;
187
-    } else if ((*points)->x != 0.) {
188
-        struct keypoint *newfirst = make_point(0, 0, *points);
189
-        if (!newfirst)
190
-            return AVERROR(ENOMEM);
191
-        *points = newfirst;
192
-    }
193
-
194
-    av_assert0(last);
195
-
196
-    /* auto insert last key point if missing at x=1 */
197
-    if (last->x != 1.) {
198
-        struct keypoint *point = make_point(1, 1, NULL);
199
-        if (!point)
200
-            return AVERROR(ENOMEM);
201
-        last->next = point;
180
+    if (*points && !(*points)->next) {
181
+        av_log(ctx, AV_LOG_WARNING, "Only one point (at (%f;%f)) is defined, "
182
+               "this is unlikely to behave as you expect. You probably want"
183
+               "at least 2 points.",
184
+               (*points)->x, (*points)->y);
202 185
     }
203 186
 
204 187
     return 0;
... ...
@@ -222,14 +205,28 @@ static int get_nb_points(const struct keypoint *d)
222 222
 static int interpolate(AVFilterContext *ctx, uint8_t *y, const struct keypoint *points)
223 223
 {
224 224
     int i, ret = 0;
225
-    const struct keypoint *point;
225
+    const struct keypoint *point = points;
226 226
     double xprev = 0;
227 227
 
228
+    double (*matrix)[3];
229
+    double *h, *r;
228 230
     int n = get_nb_points(points); // number of splines
229 231
 
230
-    double (*matrix)[3] = av_calloc(n, sizeof(*matrix));
231
-    double *h = av_malloc((n - 1) * sizeof(*h));
232
-    double *r = av_calloc(n, sizeof(*r));
232
+    if (n == 0) {
233
+        for (i = 0; i < 256; i++)
234
+            y[i] = i;
235
+        return 0;
236
+    }
237
+
238
+    if (n == 1) {
239
+        for (i = 0; i < 256; i++)
240
+            y[i] = av_clip_uint8(point->y * 255);
241
+        return 0;
242
+    }
243
+
244
+    matrix = av_calloc(n, sizeof(*matrix));
245
+    h = av_malloc((n - 1) * sizeof(*h));
246
+    r = av_calloc(n, sizeof(*r));
233 247
 
234 248
     if (!matrix || !h || !r) {
235 249
         ret = AVERROR(ENOMEM);
... ...
@@ -277,9 +274,14 @@ static int interpolate(AVFilterContext *ctx, uint8_t *y, const struct keypoint *
277 277
     for (i = n - 2; i >= 0; i--)
278 278
         r[i] = r[i] - matrix[i][AD] * r[i + 1];
279 279
 
280
-    /* compute the graph with x=[0..255] */
281
-    i = 0;
282 280
     point = points;
281
+
282
+    /* left padding */
283
+    for (i = 0; i < (int)(point->x * 255); i++)
284
+        y[i] = av_clip_uint8(point->y * 255);
285
+
286
+    /* compute the graph with x=[x0..xN] */
287
+    i = 0;
283 288
     av_assert0(point->next); // always at least 2 key points
284 289
     while (point->next) {
285 290
         double yc = point->y;
... ...
@@ -300,7 +302,7 @@ static int interpolate(AVFilterContext *ctx, uint8_t *y, const struct keypoint *
300 300
         for (x = x_start; x <= x_end; x++) {
301 301
             double xx = (x - x_start) * 1/255.;
302 302
             double yy = a + b*xx + c*xx*xx + d*xx*xx*xx;
303
-            y[x] = av_clipf(yy, 0, 1) * 255;
303
+            y[x] = av_clip_uint8(yy * 255);
304 304
             av_log(ctx, AV_LOG_DEBUG, "f(%f)=%f -> y[%d]=%d\n", xx, yy, x, y[x]);
305 305
         }
306 306
 
... ...
@@ -308,6 +310,10 @@ static int interpolate(AVFilterContext *ctx, uint8_t *y, const struct keypoint *
308 308
         i++;
309 309
     }
310 310
 
311
+    /* right padding */
312
+    for (i = (int)(point->x * 255); i <= 255; i++)
313
+        y[i] = av_clip_uint8(point->y * 255);
314
+
311 315
 end:
312 316
     av_free(matrix);
313 317
     av_free(h);