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
33
38
42 };
43
45
59 };
60
65 };
66
83
86
90
91 #define OFFSET(x) offsetof(CurvesContext, x)
92 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
121 };
122
124
125 static const struct {
132 "0.129/1 0.466/0.498 0.725/0",
133 "0.109/1 0.301/0.498 0.517/0",
134 "0.098/1 0.235/0.498 0.423/0",
135 },
137 "0/0 0.25/0.156 0.501/0.501 0.686/0.745 1/1",
138 "0/0 0.25/0.188 0.38/0.501 0.745/0.815 1/0.815",
139 "0/0 0.231/0.094 0.709/0.874 1/1",
140 },
149 "0/0.11 0.42/0.51 1/0.95",
150 "0/0 0.50/0.48 1/1",
151 "0/0.22 0.49/0.44 1/0.8",
152 }
153 };
154
156 {
158
159 if (!point)
164 return point;
165 }
166
168 int lut_size)
169 {
170 char *p = (
char *)
s;
// strtod won't alter the string
172 const int scale = lut_size - 1;
173
174 /* construct a linked list based on the key points string */
175 while (p && *p) {
177 if (!point)
179 point->
x =
av_strtod(p, &p);
if (p && *p) p++;
180 point->
y =
av_strtod(p, &p);
if (p && *p) p++;
181 if (point->
x < 0 || point->
x > 1 || point->
y < 0 || point->
y > 1) {
183 "x and y must be in the [0;1] range.\n", point->
x, point->
y);
185 }
186 if (!*points)
187 *points = point;
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);
195 }
197 }
198 last = point;
199 }
200
201 if (*points && !(*points)->
next) {
203 "this is unlikely to behave as you expect. You probably want"
204 "at least 2 points.",
205 (*points)->x, (*points)->y);
206 }
207
208 return 0;
209 }
210
212 {
213 int n = 0;
215 n++;
217 }
218 return n;
219 }
220
221 /**
222 * Natural cubic spline interpolation
223 * Finding curves using Cubic Splines notes by Steven Rauch and John Stockie.
224 * @see http://people.math.sfu.ca/~stockie/teaching/macm316/notes/splines.pdf
225 */
226
227 #define CLIP(v) (nbits == 8 ? av_clip_uint8(v) : av_clip_uintp2_c(v, nbits))
228
230 const struct keypoint *points,
int nbits)
231 {
233 const struct keypoint *point = points;
234 double xprev = 0;
235 const int lut_size = 1<<nbits;
236 const int scale = lut_size - 1;
237
241
242 if (n == 0) {
243 for (
i = 0;
i < lut_size;
i++)
245 return 0;
246 }
247
248 if (n == 1) {
249 for (
i = 0;
i < lut_size;
i++)
251 return 0;
252 }
253
257
260 goto end;
261 }
262
263 /* h(i) = x(i+1) - x(i) */
265 for (point = points; point; point = point->
next) {
267 h[
i] = point->
x - xprev;
270 }
271
272 /* right-side of the polynomials, will be modified to contains the solution */
273 point = points;
274 for (
i = 1;
i < n - 1;
i++) {
275 const double yp = point->
y;
276 const double yc = point->
next->
y;
278 r[
i] = 6 * ((yn-yc)/
h[
i] - (yc-yp)/
h[
i-1]);
280 }
281
282 #define BD 0 /* sub diagonal (below main) */
283 #define MD 1 /* main diagonal (center) */
284 #define AD 2 /* sup diagonal (above main) */
285
286 /* left side of the polynomials into a tridiagonal matrix. */
288 for (
i = 1;
i < n - 1;
i++) {
292 }
293
294 /* tridiagonal solving of the linear system */
295 for (
i = 1;
i < n;
i++) {
297 const double k = den ? 1./den : 1.;
300 }
301 for (
i = n - 2;
i >= 0;
i--)
303
304 point = points;
305
306 /* left padding */
309
310 /* compute the graph with x=[x0..xN] */
313 while (point->
next) {
314 const double yc = point->
y;
315 const double yn = point->
next->
y;
316
318 const double b = (yn-yc)/
h[
i] -
h[
i]*
r[
i]/2. -
h[
i]*(
r[
i+1]-
r[
i])/6.;
319 const double c =
r[
i] / 2.;
320 const double d = (
r[
i+1] -
r[
i]) / (6.*
h[
i]);
321
323 const int x_start = point->
x *
scale;
325
326 av_assert0(x_start >= 0 && x_start < lut_size &&
327 x_end >= 0 && x_end < lut_size);
328
329 for (
x = x_start;
x <= x_end;
x++) {
330 const double xx = (
x - x_start) * 1./
scale;
331 const double yy =
a +
b*xx +
c*xx*xx +
d*xx*xx*xx;
334 }
335
338 }
339
340 /* right padding */
341 for (
i = (
int)(point->
x *
scale);
i < lut_size;
i++)
343
344 end:
349
350 }
351
352 #define SIGN(x) (x > 0.0 ? 1 : x < 0.0 ? -1 : 0)
353
354 /**
355 * Evalaute the derivative of an edge endpoint
356 *
357 * @param h0 input interval of the interval closest to the edge
358 * @param h1 input interval of the interval next to the closest
359 * @param m0 linear slope of the interval closest to the edge
360 * @param m1 linear slope of the intervalnext to the closest
361 * @return edge endpoint derivative
362 *
363 * Based on scipy.interpolate._edge_case()
364 * https://github.com/scipy/scipy/blob/2e5883ef7af4f5ed4a5b80a1759a45e43163bf3f/scipy/interpolate/_cubic.py#L239
365 * which is a python implementation of the special case endpoints, as suggested in
366 * Cleve Moler, Numerical Computing with MATLAB, Chap 3.6 (pchiptx.m)
367 */
369 {
372
373 d = ((2 *
h0 + h1) * m0 -
h0 * m1) / (
h0 + h1);
374
377
379 else if (mask2)
d = 3.0 * m0;
380
382 }
383
384 /**
385 * Evalaute the piecewise polynomial derivatives at endpoints
386 *
387 * @param n input interval of the interval closest to the edge
388 * @param hk input intervals
389 * @param mk linear slopes over intervals
390 * @param dk endpoint derivatives (output)
391 * @return 0 success
392 *
393 * Based on scipy.interpolate._find_derivatives()
394 * https://github.com/scipy/scipy/blob/2e5883ef7af4f5ed4a5b80a1759a45e43163bf3f/scipy/interpolate/_cubic.py#L254
395 */
396
398 {
400 const int m = n - 1;
401 int8_t *smk;
402
404 if (!smk) {
406 goto end;
407 }
408
409 /* smk = sgn(mk) */
410 for (
int i = 0;
i < n;
i++) smk[
i] =
SIGN(mk[
i]);
411
412 /* check the strict monotonicity */
413 for (
int i = 0;
i < m;
i++) {
414 int8_t condition = (smk[
i + 1] != smk[
i]) || (mk[
i + 1] == 0) || (mk[
i] == 0);
415 if (condition) {
417 } else {
418 double w1 = 2 * hk[
i + 1] + hk[
i];
419 double w2 = hk[
i + 1] + 2 * hk[
i];
420 dk[
i + 1] = (w1 + w2) / (w1 / mk[
i] + w2 / mk[
i + 1]);
421 }
422 }
423
426
427 end:
429
431 }
432
433 /**
434 * Evalaute half of the cubic hermite interpolation expression, wrt one interval endpoint
435 *
436 * @param x normalized input value at the endpoint
437 * @param f output value at the endpoint
438 * @param d derivative at the endpoint: normalized to the interval, and properly sign adjusted
439 * @return half of the interpolated value
440 */
443 {
444 double x2 =
x *
x, x3 = x2 *
x;
445 return f * (3.0 * x2 - 2.0 * x3) +
d * (x3 - x2);
446 }
447
448 /**
449 * Prepare the lookup table by piecewise monotonic cubic interpolation (PCHIP)
450 *
451 * @param log_ctx for logging
452 * @param y output lookup table (output)
453 * @param points user-defined control points/endpoints
454 * @param nbits bitdepth
455 * @return 0 success
456 *
457 * References:
458 * [1] F. N. Fritsch and J. Butland, A method for constructing local monotone piecewise
459 * cubic interpolants, SIAM J. Sci. Comput., 5(2), 300-304 (1984). DOI:10.1137/0905021.
460 * [2] scipy.interpolate: https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.PchipInterpolator.html
461 */
463 const struct keypoint *points,
int nbits)
464 {
465 const struct keypoint *point = points;
466 const int lut_size = 1<<nbits;
468 double *
xi, *fi, *di, *hi, *
mi;
469 const int scale = lut_size - 1;
// white value
470 uint16_t
x;
/* input index/value */
472
473 /* no change for n = 0 or 1 */
474 if (n == 0) {
475 /* no points, no change */
476 for (
int i = 0;
i < lut_size;
i++)
y[
i] =
i;
477 return 0;
478 }
479
480 if (n == 1) {
481 /* 1 point - 1 color everywhere */
483 for (
int i = 0;
i < lut_size;
i++)
y[
i] = yval;
484 return 0;
485 }
486
487 xi =
av_calloc(3*n + 2*(n-1),
sizeof(
double));
/* output values at interval endpoints */
490 goto end;
491 }
492
493 fi =
xi + n;
/* output values at inteval endpoints */
494 di = fi + n; /* output slope wrt normalized input at interval endpoints */
495 hi = di + n; /* interval widths */
496 mi = hi + n - 1;
/* linear slope over intervals */
497
498 /* scale endpoints and store them in a contiguous memory block */
499 for (
int i = 0;
i < n;
i++) {
503 }
504
505 /* h(i) = x(i+1) - x(i); mi(i) = (f(i+1)-f(i))/h(i) */
506 for (
int i = 0;
i < n - 1;
i++) {
510 }
511
512 if (n == 2) {
513 /* edge case, use linear interpolation */
514 const double m =
mi[0],
b = fi[0] -
xi[0]*m;
515 for (
int i = 0;
i < lut_size;
i++)
y[
i] =
CLIP(
i*m +
b);
516 goto end;
517 }
518
519 /* compute the derivatives at the endpoints*/
522 goto end;
523
524 /* interpolate/extrapolate */
527 /* below first endpoint, use the first endpoint value*/
528 const double xi0 =
xi[0];
529 const double yi0 = fi[0];
530 const uint16_t yval =
CLIP(yi0);
531 for (;
x < xi0;
x++) {
534 }
536 }
537
538 /* for each interval */
539 for (
int i = 0, x0 =
x;
i < n-1;
i++, x0 =
x) {
540 const double xi0 =
xi[
i];
/* start-of-interval input value */
541 const double xi1 =
xi[
i + 1];
/* end-of-interval input value */
542 const double h = hi[
i];
/* interval width */
543 const double f0 = fi[
i];
/* start-of-interval output value */
544 const double f1 = fi[
i + 1];
/* end-of-interval output value */
545 const double d0 = di[
i];
/* start-of-interval derivative */
546 const double d1 = di[
i + 1];
/* end-of-interval derivative */
547
548 /* fill the lut over the interval */
549 for (;
x < xi1;
x++) {
/* safe not to check j < lut_size */
550 const double xx = (
x - xi0) /
h;
/* normalize input */
555 }
556
559 i, x0,
x-1,
y[x0],
y[
x-1]);
560 else
562 }
563
564 if (
x &&
x < lut_size) {
565 /* above the last endpoint, use the last endpoint value*/
566 const double xi1 =
xi[n - 1];
567 const double yi1 = fi[n - 1];
568 const uint16_t yval =
CLIP(yi1);
570 n-1,
x, lut_size - 1, yval);
571 for (;
x &&
x < lut_size;
x++) {
/* loop until int overflow */
574 }
575 }
576
577 end:
580 }
581
582
584 {
586 uint8_t *buf;
589 AVBPrint ptstr;
590 static const int comp_ids[] = {3, 0, 1, 2};
591
593
597
598 #define READ16(dst) do { \
599 if (size < 2) { \
600 ret = AVERROR_INVALIDDATA; \
601 goto end; \
602 } \
603 dst = AV_RB16(buf); \
604 buf += 2; \
605 size -= 2; \
606 } while (0)
607
611 int nb_points, n;
614 for (n = 0; n < nb_points; n++) {
619 }
620 if (*ptstr.str) {
621 char **
pts = &
curves->comp_points_str[comp_ids[
i]];
625 i, comp_ids[
i], nb_points, *
pts);
628 goto end;
629 }
630 }
631 }
632 }
633 end:
637 }
638
641 int lut_size)
642 {
644 AVBPrint buf;
645 const double scale = 1. / (lut_size - 1);
646 static const char * const colors[] = { "red", "green", "blue", "#404040", };
648
650
656 }
657
659
664
666 av_bprintf(&buf,
"%s'-' using 1:2 with lines lc '%s' title ''",
667 i ?
", " :
"plot ", colors[
i]);
669 av_bprintf(&buf,
", '-' using 1:2 with points pointtype 3 lc '%s' title ''",
671 }
673
676
677 /* plot generated values */
678 for (
x = 0;
x < lut_size;
x++)
681
682 /* plot user knots */
683 if (comp_points[
i]) {
684 const struct keypoint *point = comp_points[
i];
685
686 while (point) {
689 }
691 }
692 }
693
694 fwrite(buf.str, 1, buf.len,
f);
697 return 0;
698 }
699
701 {
705 const char *allp =
curves->comp_points_str_all;
706
707 //if (!allp && curves->preset != PRESET_NONE && curves_presets[curves->preset].all)
708 // allp = curves_presets[curves->preset].all;
709
710 if (allp) {
716 }
717 }
718
723 curves->parsed_psfile = 1;
724 }
725
727 #define SET_COMP_IF_NOT_SET(n, name) do { \
728 if (!pts[n] && curves_presets[curves->preset].name) { \
729 pts[n] = av_strdup(curves_presets[curves->preset].name); \
730 if (!pts[n]) \
731 return AVERROR(ENOMEM); \
732 } \
733 } while (0)
739 }
740
741 return 0;
742 }
743
745 {
751 const int direct =
out == in;
753 const uint8_t
r =
curves->rgba_map[
R];
754 const uint8_t
g =
curves->rgba_map[
G];
755 const uint8_t
b =
curves->rgba_map[
B];
756 const uint8_t
a =
curves->rgba_map[
A];
759
762 uint16_t *dstp = ( uint16_t *)(
out->data[0] +
y *
out->linesize[0]);
763 const uint16_t *srcp = (
const uint16_t *)(in ->
data[0] +
y * in->
linesize[0]);
764
769 if (!direct &&
step == 4)
770 dstp[
x +
a] = srcp[
x +
a];
771 }
772 }
773 } else {
776
782 if (!direct &&
step == 4)
784 }
785 dst +=
out->linesize[0];
787 }
788 }
789 return 0;
790 }
791
793 {
799 const int direct =
out == in;
801 const uint8_t
r =
curves->rgba_map[
R];
802 const uint8_t
g =
curves->rgba_map[
G];
803 const uint8_t
b =
curves->rgba_map[
B];
804 const uint8_t
a =
curves->rgba_map[
A];
807
810 uint16_t *dstrp = ( uint16_t *)(
out->data[
r] +
y *
out->linesize[
r]);
811 uint16_t *dstgp = ( uint16_t *)(
out->data[
g] +
y *
out->linesize[
g]);
812 uint16_t *dstbp = ( uint16_t *)(
out->data[
b] +
y *
out->linesize[
b]);
813 uint16_t *dstap = ( uint16_t *)(
out->data[
a] +
y *
out->linesize[
a]);
814 const uint16_t *srcrp = (
const uint16_t *)(in ->
data[
r] +
y * in->
linesize[
r]);
815 const uint16_t *srcgp = (
const uint16_t *)(in ->
data[
g] +
y * in->
linesize[
g]);
816 const uint16_t *srcbp = (
const uint16_t *)(in ->
data[
b] +
y * in->
linesize[
b]);
817 const uint16_t *srcap = (
const uint16_t *)(in ->
data[
a] +
y * in->
linesize[
a]);
818
823 if (!direct &&
step == 4)
825 }
826 }
827 } else {
836
842 if (!direct &&
step == 4)
844 }
845 dstr +=
out->linesize[
r];
846 dstg +=
out->linesize[
g];
847 dstb +=
out->linesize[
b];
848 dsta +=
out->linesize[
a];
853 }
854 }
855 return 0;
856 }
857
859 {
866
873
884 else
888 }
889
892 for (j = 0; j <
curves->lut_size; j++)
894 }
895
898 const struct keypoint *point = comp_points[
i];
900 while (point) {
903 }
904 }
905 }
906
910 }
911
914 while (point) {
918 }
919 }
920
921 return 0;
922 }
923
925 {
931
934 } else {
939 }
941 }
942
947
950
952 }
953
955 char *res,
int res_len,
int flags)
956 {
959
960 if (!strcmp(cmd, "plot")) {
962 } else if (!strcmp(cmd, "all") || !strcmp(cmd, "preset") || !strcmp(cmd, "psfile") || !strcmp(cmd, "interp")) {
963 if (!strcmp(cmd, "psfile"))
964 curves->parsed_psfile = 0;
970 } else if (!strcmp(cmd, "red") || !strcmp(cmd, "r")) {
972 } else if (!strcmp(cmd, "green") || !strcmp(cmd, "g")) {
974 } else if (!strcmp(cmd, "blue") || !strcmp(cmd, "b")) {
976 } else if (!strcmp(cmd, "master") || !strcmp(cmd, "m")) {
978 }
979
983
988 }
989
991 {
994
997 }
998
1000 {
1005 },
1006 };
1007
1029 .priv_class = &curves_class,
1032 };