Commit 5c14018f authored by Clément Bœsch's avatar Clément Bœsch

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
parent 783a2568
...@@ -7,6 +7,7 @@ version <next>: ...@@ -7,6 +7,7 @@ version <next>:
- Changed metadata print option to accept general urls - Changed metadata print option to accept general urls
- Alias muxer for Ogg Video (.ogv) - Alias muxer for Ogg Video (.ogv)
- VP8 in Ogg muxing - VP8 in Ogg muxing
- curves filter doesn't automatically insert points at x=0 and x=1 anymore
version 3.1: version 3.1:
......
...@@ -5710,10 +5710,6 @@ strictly increasing over the x-axis, and their @var{x} and @var{y} values must ...@@ -5710,10 +5710,6 @@ strictly increasing over the x-axis, and their @var{x} and @var{y} values must
be in the @var{[0;1]} interval. If the computed curves happened to go outside be in the @var{[0;1]} interval. If the computed curves happened to go outside
the vector spaces, the values will be clipped accordingly. the vector spaces, the values will be clipped accordingly.
If there is no key point defined in @code{x=0}, the filter will automatically
insert a @var{(0;0)} point. In the same way, if there is no key point defined
in @code{x=1}, the filter will automatically insert a @var{(1;1)} point.
The filter accepts the following options: The filter accepts the following options:
@table @option @table @option
...@@ -5765,13 +5761,13 @@ defined using the following syntax: @code{x0/y0 x1/y1 x2/y2 ...}. ...@@ -5765,13 +5761,13 @@ defined using the following syntax: @code{x0/y0 x1/y1 x2/y2 ...}.
@item @item
Increase slightly the middle level of blue: Increase slightly the middle level of blue:
@example @example
curves=blue='0.5/0.58' curves=blue='0/0 0.5/0.58 1/1'
@end example @end example
@item @item
Vintage effect: Vintage effect:
@example @example
curves=r='0/0.11 .42/.51 1/0.95':g='0.50/0.48':b='0/0.22 .49/.44 1/0.8' 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'
@end example @end example
Here we obtain the following coordinates for each components: Here we obtain the following coordinates for each components:
@table @var @table @var
...@@ -5798,7 +5794,7 @@ curves=vintage ...@@ -5798,7 +5794,7 @@ curves=vintage
@item @item
Use a Photoshop preset and redefine the points of the green component: Use a Photoshop preset and redefine the points of the green component:
@example @example
curves=psfile='MyCurvesPresets/purple.acv':green='0.45/0.53' curves=psfile='MyCurvesPresets/purple.acv':green='0/0 0.45/0.53 1/1'
@end example @end example
@end itemize @end itemize
......
...@@ -110,25 +110,25 @@ static const struct { ...@@ -110,25 +110,25 @@ static const struct {
const char *master; const char *master;
} curves_presets[] = { } curves_presets[] = {
[PRESET_COLOR_NEGATIVE] = { [PRESET_COLOR_NEGATIVE] = {
"0/1 0.129/1 0.466/0.498 0.725/0 1/0", "0.129/1 0.466/0.498 0.725/0",
"0/1 0.109/1 0.301/0.498 0.517/0 1/0", "0.109/1 0.301/0.498 0.517/0",
"0/1 0.098/1 0.235/0.498 0.423/0 1/0", "0.098/1 0.235/0.498 0.423/0",
}, },
[PRESET_CROSS_PROCESS] = { [PRESET_CROSS_PROCESS] = {
"0.25/0.156 0.501/0.501 0.686/0.745", "0/0 0.25/0.156 0.501/0.501 0.686/0.745 1/1",
"0.25/0.188 0.38/0.501 0.745/0.815 1/0.815", "0/0 0.25/0.188 0.38/0.501 0.745/0.815 1/0.815",
"0.231/0.094 0.709/0.874", "0/0 0.231/0.094 0.709/0.874 1/1",
}, },
[PRESET_DARKER] = { .master = "0.5/0.4" }, [PRESET_DARKER] = { .master = "0/0 0.5/0.4 1/1" },
[PRESET_INCREASE_CONTRAST] = { .master = "0.149/0.066 0.831/0.905 0.905/0.98" }, [PRESET_INCREASE_CONTRAST] = { .master = "0/0 0.149/0.066 0.831/0.905 0.905/0.98 1/1" },
[PRESET_LIGHTER] = { .master = "0.4/0.5" }, [PRESET_LIGHTER] = { .master = "0/0 0.4/0.5 1/1" },
[PRESET_LINEAR_CONTRAST] = { .master = "0.305/0.286 0.694/0.713" }, [PRESET_LINEAR_CONTRAST] = { .master = "0/0 0.305/0.286 0.694/0.713 1/1" },
[PRESET_MEDIUM_CONTRAST] = { .master = "0.286/0.219 0.639/0.643" }, [PRESET_MEDIUM_CONTRAST] = { .master = "0/0 0.286/0.219 0.639/0.643 1/1" },
[PRESET_NEGATIVE] = { .master = "0/1 1/0" }, [PRESET_NEGATIVE] = { .master = "0/1 1/0" },
[PRESET_STRONG_CONTRAST] = { .master = "0.301/0.196 0.592/0.6 0.686/0.737" }, [PRESET_STRONG_CONTRAST] = { .master = "0/0 0.301/0.196 0.592/0.6 0.686/0.737 1/1" },
[PRESET_VINTAGE] = { [PRESET_VINTAGE] = {
"0/0.11 0.42/0.51 1/0.95", "0/0.11 0.42/0.51 1/0.95",
"0.50/0.48", "0/0 0.50/0.48 1/1",
"0/0.22 0.49/0.44 1/0.8", "0/0.22 0.49/0.44 1/0.8",
} }
}; };
...@@ -177,28 +177,11 @@ static int parse_points_str(AVFilterContext *ctx, struct keypoint **points, cons ...@@ -177,28 +177,11 @@ static int parse_points_str(AVFilterContext *ctx, struct keypoint **points, cons
last = point; last = point;
} }
/* auto insert first key point if missing at x=0 */ if (*points && !(*points)->next) {
if (!*points) { av_log(ctx, AV_LOG_WARNING, "Only one point (at (%f;%f)) is defined, "
last = make_point(0, 0, NULL); "this is unlikely to behave as you expect. You probably want"
if (!last) "at least 2 points.",
return AVERROR(ENOMEM); (*points)->x, (*points)->y);
last->x = last->y = 0;
*points = last;
} else if ((*points)->x != 0.) {
struct keypoint *newfirst = make_point(0, 0, *points);
if (!newfirst)
return AVERROR(ENOMEM);
*points = newfirst;
}
av_assert0(last);
/* auto insert last key point if missing at x=1 */
if (last->x != 1.) {
struct keypoint *point = make_point(1, 1, NULL);
if (!point)
return AVERROR(ENOMEM);
last->next = point;
} }
return 0; return 0;
...@@ -222,14 +205,28 @@ static int get_nb_points(const struct keypoint *d) ...@@ -222,14 +205,28 @@ static int get_nb_points(const struct keypoint *d)
static int interpolate(AVFilterContext *ctx, uint8_t *y, const struct keypoint *points) static int interpolate(AVFilterContext *ctx, uint8_t *y, const struct keypoint *points)
{ {
int i, ret = 0; int i, ret = 0;
const struct keypoint *point; const struct keypoint *point = points;
double xprev = 0; double xprev = 0;
double (*matrix)[3];
double *h, *r;
int n = get_nb_points(points); // number of splines int n = get_nb_points(points); // number of splines
double (*matrix)[3] = av_calloc(n, sizeof(*matrix)); if (n == 0) {
double *h = av_malloc((n - 1) * sizeof(*h)); for (i = 0; i < 256; i++)
double *r = av_calloc(n, sizeof(*r)); y[i] = i;
return 0;
}
if (n == 1) {
for (i = 0; i < 256; i++)
y[i] = av_clip_uint8(point->y * 255);
return 0;
}
matrix = av_calloc(n, sizeof(*matrix));
h = av_malloc((n - 1) * sizeof(*h));
r = av_calloc(n, sizeof(*r));
if (!matrix || !h || !r) { if (!matrix || !h || !r) {
ret = AVERROR(ENOMEM); ret = AVERROR(ENOMEM);
...@@ -277,9 +274,14 @@ static int interpolate(AVFilterContext *ctx, uint8_t *y, const struct keypoint * ...@@ -277,9 +274,14 @@ static int interpolate(AVFilterContext *ctx, uint8_t *y, const struct keypoint *
for (i = n - 2; i >= 0; i--) for (i = n - 2; i >= 0; i--)
r[i] = r[i] - matrix[i][AD] * r[i + 1]; r[i] = r[i] - matrix[i][AD] * r[i + 1];
/* compute the graph with x=[0..255] */
i = 0;
point = points; point = points;
/* left padding */
for (i = 0; i < (int)(point->x * 255); i++)
y[i] = av_clip_uint8(point->y * 255);
/* compute the graph with x=[x0..xN] */
i = 0;
av_assert0(point->next); // always at least 2 key points av_assert0(point->next); // always at least 2 key points
while (point->next) { while (point->next) {
double yc = point->y; double yc = point->y;
...@@ -300,7 +302,7 @@ static int interpolate(AVFilterContext *ctx, uint8_t *y, const struct keypoint * ...@@ -300,7 +302,7 @@ static int interpolate(AVFilterContext *ctx, uint8_t *y, const struct keypoint *
for (x = x_start; x <= x_end; x++) { for (x = x_start; x <= x_end; x++) {
double xx = (x - x_start) * 1/255.; double xx = (x - x_start) * 1/255.;
double yy = a + b*xx + c*xx*xx + d*xx*xx*xx; double yy = a + b*xx + c*xx*xx + d*xx*xx*xx;
y[x] = av_clipf(yy, 0, 1) * 255; y[x] = av_clip_uint8(yy * 255);
av_log(ctx, AV_LOG_DEBUG, "f(%f)=%f -> y[%d]=%d\n", xx, yy, x, y[x]); av_log(ctx, AV_LOG_DEBUG, "f(%f)=%f -> y[%d]=%d\n", xx, yy, x, y[x]);
} }
...@@ -308,6 +310,10 @@ static int interpolate(AVFilterContext *ctx, uint8_t *y, const struct keypoint * ...@@ -308,6 +310,10 @@ static int interpolate(AVFilterContext *ctx, uint8_t *y, const struct keypoint *
i++; i++;
} }
/* right padding */
for (i = (int)(point->x * 255); i <= 255; i++)
y[i] = av_clip_uint8(point->y * 255);
end: end:
av_free(matrix); av_free(matrix);
av_free(h); av_free(h);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment