1 /*
2 * Copyright (c) 2013 Clément Bœsch
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg 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.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg 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 FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
34
39
43 };
44
46
60 };
61
66 };
67
84
87
91
92 #define OFFSET(x) offsetof(CurvesContext, x)
93 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
122 };
123
125
126 static const struct {
133 "0.129/1 0.466/0.498 0.725/0",
134 "0.109/1 0.301/0.498 0.517/0",
135 "0.098/1 0.235/0.498 0.423/0",
136 },
138 "0/0 0.25/0.156 0.501/0.501 0.686/0.745 1/1",
139 "0/0 0.25/0.188 0.38/0.501 0.745/0.815 1/0.815",
140 "0/0 0.231/0.094 0.709/0.874 1/1",
141 },
150 "0/0.11 0.42/0.51 1/0.95",
151 "0/0 0.50/0.48 1/1",
152 "0/0.22 0.49/0.44 1/0.8",
153 }
154 };
155
157 {
159
160 if (!point)
165 return point;
166 }
167
169 int lut_size)
170 {
171 char *
p = (
char *)
s;
// strtod won't alter the string
173 const int scale = lut_size - 1;
174
175 /* construct a linked list based on the key points string */
178 if (!point)
182 if (point->
x < 0 || point->
x > 1 || point->
y < 0 || point->
y > 1) {
184 "x and y must be in the [0;1] range.\n", point->
x, point->
y);
187 }
188 if (last) {
189 if ((
int)(last->
x *
scale) >= (
int)(point->
x *
scale)) {
191 "and (%f;%f) are too close from each other or not "
192 "strictly increasing on the x-axis\n",
193 last->
x, last->
y, point->
x, point->
y);
196 }
198 }
199 if (!*points)
200 *points = point;
201 last = point;
202 }
203
204 if (*points && !(*points)->
next) {
206 "this is unlikely to behave as you expect. You probably want"
207 "at least 2 points.",
208 (*points)->x, (*points)->y);
209 }
210
211 return 0;
212 }
213
215 {
216 int n = 0;
217 while (d) {
218 n++;
220 }
221 return n;
222 }
223
224 /**
225 * Natural cubic spline interpolation
226 * Finding curves using Cubic Splines notes by Steven Rauch and John Stockie.
227 * @see http://people.math.sfu.ca/~stockie/teaching/macm316/notes/splines.pdf
228 */
229
230 #define CLIP(v) (nbits == 8 ? av_clip_uint8(v) : av_clip_uintp2_c(v, nbits))
231
233 const struct keypoint *points,
int nbits)
234 {
236 const struct keypoint *point = points;
237 double xprev = 0;
238 const int lut_size = 1<<nbits;
239 const int scale = lut_size - 1;
240
244
245 if (n == 0) {
246 for (
i = 0;
i < lut_size;
i++)
248 return 0;
249 }
250
251 if (n == 1) {
252 for (
i = 0;
i < lut_size;
i++)
254 return 0;
255 }
256
260
263 goto end;
264 }
265
266 /* h(i) = x(i+1) - x(i) */
268 for (point = points; point; point = point->
next) {
270 h[
i] = point->
x - xprev;
273 }
274
275 /* right-side of the polynomials, will be modified to contains the solution */
276 point = points;
277 for (
i = 1;
i < n - 1;
i++) {
278 const double yp = point->
y;
279 const double yc = point->
next->
y;
281 r[
i] = 6 * ((yn-yc)/
h[
i] - (yc-yp)/
h[
i-1]);
283 }
284
285 #define BD 0 /* sub diagonal (below main) */
286 #define MD 1 /* main diagonal (center) */
287 #define AD 2 /* sup diagonal (above main) */
288
289 /* left side of the polynomials into a tridiagonal matrix. */
291 for (
i = 1;
i < n - 1;
i++) {
295 }
296
297 /* tridiagonal solving of the linear system */
298 for (
i = 1;
i < n;
i++) {
300 const double k = den ? 1./den : 1.;
303 }
304 for (
i = n - 2;
i >= 0;
i--)
306
307 point = points;
308
309 /* left padding */
310 for (
i = 0;
i < (int)(point->
x *
scale);
i++)
312
313 /* compute the graph with x=[x0..xN] */
316 while (point->
next) {
317 const double yc = point->
y;
318 const double yn = point->
next->
y;
319
321 const double b = (yn-yc)/
h[
i] -
h[
i]*
r[
i]/2. -
h[
i]*(
r[
i+1]-
r[
i])/6.;
322 const double c =
r[
i] / 2.;
323 const double d = (
r[
i+1] -
r[
i]) / (6.*
h[
i]);
324
326 const int x_start = point->
x *
scale;
328
329 av_assert0(x_start >= 0 && x_start < lut_size &&
330 x_end >= 0 && x_end < lut_size);
331
332 for (
x = x_start;
x <= x_end;
x++) {
333 const double xx = (
x - x_start) * 1./
scale;
334 const double yy =
a +
b*xx +
c*xx*xx + d*xx*xx*xx;
337 }
338
341 }
342
343 /* right padding */
344 for (
i = (
int)(point->
x *
scale);
i < lut_size;
i++)
346
347 end:
352
353 }
354
355 #define SIGN(x) (x > 0.0 ? 1 : x < 0.0 ? -1 : 0)
356
357 /**
358 * Evalaute the derivative of an edge endpoint
359 *
360 * @param h0 input interval of the interval closest to the edge
361 * @param h1 input interval of the interval next to the closest
362 * @param m0 linear slope of the interval closest to the edge
363 * @param m1 linear slope of the intervalnext to the closest
364 * @return edge endpoint derivative
365 *
366 * Based on scipy.interpolate._edge_case()
367 * https://github.com/scipy/scipy/blob/2e5883ef7af4f5ed4a5b80a1759a45e43163bf3f/scipy/interpolate/_cubic.py#L239
368 * which is a python implementation of the special case endpoints, as suggested in
369 * Cleve Moler, Numerical Computing with MATLAB, Chap 3.6 (pchiptx.m)
370 */
372 {
374 double d;
375
376 d = ((2 *
h0 + h1) * m0 -
h0 * m1) / (
h0 + h1);
377
380
382 else if (mask2) d = 3.0 * m0;
383
384 return d;
385 }
386
387 /**
388 * Evalaute the piecewise polynomial derivatives at endpoints
389 *
390 * @param n input interval of the interval closest to the edge
391 * @param hk input intervals
392 * @param mk linear slopes over intervals
393 * @param dk endpoint derivatives (output)
394 * @return 0 success
395 *
396 * Based on scipy.interpolate._find_derivatives()
397 * https://github.com/scipy/scipy/blob/2e5883ef7af4f5ed4a5b80a1759a45e43163bf3f/scipy/interpolate/_cubic.py#L254
398 */
399
401 {
403 const int m = n - 1;
404 int8_t *smk;
405
407 if (!smk) {
409 goto end;
410 }
411
412 /* smk = sgn(mk) */
413 for (
int i = 0;
i < n;
i++) smk[
i] =
SIGN(mk[
i]);
414
415 /* check the strict monotonicity */
416 for (
int i = 0;
i < m;
i++) {
417 int8_t condition = (smk[
i + 1] != smk[
i]) || (mk[
i + 1] == 0) || (mk[
i] == 0);
418 if (condition) {
420 } else {
421 double w1 = 2 * hk[
i + 1] + hk[
i];
422 double w2 = hk[
i + 1] + 2 * hk[
i];
423 dk[
i + 1] = (w1 + w2) / (w1 / mk[
i] + w2 / mk[
i + 1]);
424 }
425 }
426
429
430 end:
432
434 }
435
436 /**
437 * Evalaute half of the cubic hermite interpolation expression, wrt one interval endpoint
438 *
439 * @param x normalized input value at the endpoint
440 * @param f output value at the endpoint
441 * @param d derivative at the endpoint: normalized to the interval, and properly sign adjusted
442 * @return half of the interpolated value
443 */
445 const double d)
446 {
447 double x2 =
x *
x, x3 = x2 *
x;
448 return f * (3.0 * x2 - 2.0 * x3) + d * (x3 - x2);
449 }
450
451 /**
452 * Prepare the lookup table by piecewise monotonic cubic interpolation (PCHIP)
453 *
454 * @param log_ctx for logging
455 * @param y output lookup table (output)
456 * @param points user-defined control points/endpoints
457 * @param nbits bitdepth
458 * @return 0 success
459 *
460 * References:
461 * [1] F. N. Fritsch and J. Butland, A method for constructing local monotone piecewise
462 * cubic interpolants, SIAM J. Sci. Comput., 5(2), 300-304 (1984). DOI:10.1137/0905021.
463 * [2] scipy.interpolate: https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.PchipInterpolator.html
464 */
466 const struct keypoint *points,
int nbits)
467 {
468 const struct keypoint *point = points;
469 const int lut_size = 1<<nbits;
471 double *
xi, *fi, *di, *hi, *
mi;
472 const int scale = lut_size - 1;
// white value
473 uint16_t
x;
/* input index/value */
475
476 /* no change for n = 0 or 1 */
477 if (n == 0) {
478 /* no points, no change */
479 for (
int i = 0;
i < lut_size;
i++)
y[
i] =
i;
480 return 0;
481 }
482
483 if (n == 1) {
484 /* 1 point - 1 color everywhere */
486 for (
int i = 0;
i < lut_size;
i++)
y[
i] = yval;
487 return 0;
488 }
489
490 xi =
av_calloc(3*n + 2*(n-1),
sizeof(
double));
/* output values at interval endpoints */
493 goto end;
494 }
495
496 fi =
xi + n;
/* output values at interval endpoints */
497 di = fi + n; /* output slope wrt normalized input at interval endpoints */
498 hi = di + n; /* interval widths */
499 mi = hi + n - 1;
/* linear slope over intervals */
500
501 /* scale endpoints and store them in a contiguous memory block */
502 for (
int i = 0;
i < n;
i++) {
506 }
507
508 /* h(i) = x(i+1) - x(i); mi(i) = (f(i+1)-f(i))/h(i) */
509 for (
int i = 0;
i < n - 1;
i++) {
513 }
514
515 if (n == 2) {
516 /* edge case, use linear interpolation */
517 const double m =
mi[0],
b = fi[0] -
xi[0]*m;
518 for (
int i = 0;
i < lut_size;
i++)
y[
i] =
CLIP(
i*m +
b);
519 goto end;
520 }
521
522 /* compute the derivatives at the endpoints*/
525 goto end;
526
527 /* interpolate/extrapolate */
530 /* below first endpoint, use the first endpoint value*/
531 const double xi0 =
xi[0];
532 const double yi0 = fi[0];
533 const uint16_t yval =
CLIP(yi0);
534 for (;
x < xi0;
x++) {
537 }
539 }
540
541 /* for each interval */
542 for (
int i = 0, x0 =
x;
i < n-1;
i++, x0 =
x) {
543 const double xi0 =
xi[
i];
/* start-of-interval input value */
544 const double xi1 =
xi[
i + 1];
/* end-of-interval input value */
545 const double h = hi[
i];
/* interval width */
546 const double f0 = fi[
i];
/* start-of-interval output value */
547 const double f1 = fi[
i + 1];
/* end-of-interval output value */
548 const double d0 = di[
i];
/* start-of-interval derivative */
549 const double d1 = di[
i + 1];
/* end-of-interval derivative */
550
551 /* fill the lut over the interval */
552 for (;
x < xi1;
x++) {
/* safe not to check j < lut_size */
553 const double xx = (
x - xi0) /
h;
/* normalize input */
558 }
559
562 i, x0,
x-1,
y[x0],
y[
x-1]);
563 else
565 }
566
567 if (
x &&
x < lut_size) {
568 /* above the last endpoint, use the last endpoint value*/
569 const double xi1 =
xi[n - 1];
570 const double yi1 = fi[n - 1];
571 const uint16_t yval =
CLIP(yi1);
573 n-1,
x, lut_size - 1, yval);
574 for (;
x &&
x < lut_size;
x++) {
/* loop until int overflow */
577 }
578 }
579
580 end:
583 }
584
585
587 {
589 uint8_t *buf;
592 AVBPrint ptstr;
593 static const int comp_ids[] = {3, 0, 1, 2};
594
596
600
601 #define READ16(dst) do { \
602 if (size < 2) { \
603 ret = AVERROR_INVALIDDATA; \
604 goto end; \
605 } \
606 dst = AV_RB16(buf); \
607 buf += 2; \
608 size -= 2; \
609 } while (0)
610
614 int nb_points, n;
617 for (n = 0; n < nb_points; n++) {
622 }
623 if (*ptstr.str) {
624 char **
pts = &
curves->comp_points_str[comp_ids[
i]];
628 i, comp_ids[
i], nb_points, *
pts);
631 goto end;
632 }
633 }
634 }
635 }
636 end:
640 }
641
644 int lut_size, void *log_ctx)
645 {
647 AVBPrint buf;
648 const double scale = 1. / (lut_size - 1);
649 static const char * const colors[] = { "red", "green", "blue", "#404040", };
651
653
659 }
660
662
667
669 av_bprintf(&buf,
"%s'-' using 1:2 with lines lc '%s' title ''",
670 i ?
", " :
"plot ", colors[
i]);
672 av_bprintf(&buf,
", '-' using 1:2 with points pointtype 3 lc '%s' title ''",
674 }
676
679
680 /* plot generated values */
681 for (
x = 0;
x < lut_size;
x++)
684
685 /* plot user knots */
686 if (comp_points[
i]) {
687 const struct keypoint *point = comp_points[
i];
688
689 while (point) {
692 }
694 }
695 }
696
697 fwrite(buf.str, 1, buf.len,
f);
700 return 0;
701 }
702
704 {
708 const char *allp =
curves->comp_points_str_all;
709
710 //if (!allp && curves->preset != PRESET_NONE && curves_presets[curves->preset].all)
711 // allp = curves_presets[curves->preset].all;
712
713 if (allp) {
719 }
720 }
721
726 curves->parsed_psfile = 1;
727 }
728
730 #define SET_COMP_IF_NOT_SET(n, name) do { \
731 if (!pts[n] && curves_presets[curves->preset].name) { \
732 pts[n] = av_strdup(curves_presets[curves->preset].name); \
733 if (!pts[n]) \
734 return AVERROR(ENOMEM); \
735 } \
736 } while (0)
742 }
743
744 return 0;
745 }
746
748 {
754 const int direct =
out == in;
756 const uint8_t
r =
curves->rgba_map[
R];
757 const uint8_t
g =
curves->rgba_map[
G];
758 const uint8_t
b =
curves->rgba_map[
B];
759 const uint8_t
a =
curves->rgba_map[
A];
762
765 uint16_t *dstp = ( uint16_t *)(
out->data[0] +
y *
out->linesize[0]);
766 const uint16_t *srcp = (
const uint16_t *)(in ->
data[0] +
y * in->
linesize[0]);
767
772 if (!direct &&
step == 4)
773 dstp[
x +
a] = srcp[
x +
a];
774 }
775 }
776 } else {
779
785 if (!direct &&
step == 4)
787 }
790 }
791 }
792 return 0;
793 }
794
796 {
802 const int direct =
out == in;
804 const uint8_t
r =
curves->rgba_map[
R];
805 const uint8_t
g =
curves->rgba_map[
G];
806 const uint8_t
b =
curves->rgba_map[
B];
807 const uint8_t
a =
curves->rgba_map[
A];
810
813 uint16_t *dstrp = ( uint16_t *)(
out->data[
r] +
y *
out->linesize[
r]);
814 uint16_t *dstgp = ( uint16_t *)(
out->data[
g] +
y *
out->linesize[
g]);
815 uint16_t *dstbp = ( uint16_t *)(
out->data[
b] +
y *
out->linesize[
b]);
816 uint16_t *dstap = ( uint16_t *)(
step == 4 ?
out->data[
a] +
y *
out->linesize[
a] :
NULL);
817 const uint16_t *srcrp = (
const uint16_t *)(in ->
data[
r] +
y * in->
linesize[
r]);
818 const uint16_t *srcgp = (
const uint16_t *)(in ->
data[
g] +
y * in->
linesize[
g]);
819 const uint16_t *srcbp = (
const uint16_t *)(in ->
data[
b] +
y * in->
linesize[
b]);
821
826 if (!direct &&
step == 4)
828 }
829 }
830 } else {
834 uint8_t *dsta =
step == 4 ?
out->data[
a]
839 const uint8_t *srca =
step == 4 ? in->
data[
a]
841
847 if (!direct &&
step == 4)
849 }
850 dstr +=
out->linesize[
r];
851 dstg +=
out->linesize[
g];
852 dstb +=
out->linesize[
b];
857 dsta +=
out->linesize[
a];
859 }
860 }
861 }
862 return 0;
863 }
864
866 {
873
880
891 else
895 }
896
899 for (j = 0; j <
curves->lut_size; j++)
901 }
902
905 const struct keypoint *point = comp_points[
i];
907 while (point) {
910 }
911 }
912 }
913
917 }
918
921 while (point) {
925 }
926 }
927
928 return 0;
929 }
930
932 {
938
941 } else {
946 }
948 }
949
954
957
959 }
960
962 char *res,
int res_len,
int flags)
963 {
966
967 if (!strcmp(cmd, "plot")) {
969 } else if (!strcmp(cmd, "all") || !strcmp(cmd, "preset") || !strcmp(cmd, "psfile") || !strcmp(cmd, "interp")) {
970 if (!strcmp(cmd, "psfile"))
971 curves->parsed_psfile = 0;
977 } else if (!strcmp(cmd, "red") || !strcmp(cmd, "r")) {
979 } else if (!strcmp(cmd, "green") || !strcmp(cmd, "g")) {
981 } else if (!strcmp(cmd, "blue") || !strcmp(cmd, "b")) {
983 } else if (!strcmp(cmd, "master") || !strcmp(cmd, "m")) {
985 }
986
990
995 }
996
998 {
1001
1004 }
1005
1007 {
1012 },
1013 };
1014
1018 .p.priv_class = &curves_class,
1039 };