FFmpeg
vf_curves.c
Go to the documentation of this file.
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 
21 #include "libavutil/opt.h"
22 #include "libavutil/bprint.h"
23 #include "libavutil/eval.h"
24 #include "libavutil/file.h"
25 #include "libavutil/file_open.h"
26 #include "libavutil/intreadwrite.h"
27 #include "libavutil/avassert.h"
28 #include "libavutil/pixdesc.h"
29 #include "avfilter.h"
30 #include "drawutils.h"
31 #include "internal.h"
32 #include "video.h"
33 
34 #define R 0
35 #define G 1
36 #define B 2
37 #define A 3
38 
39 struct keypoint {
40  double x, y;
41  struct keypoint *next;
42 };
43 
44 #define NB_COMP 3
45 
46 enum preset {
59 };
60 
61 enum interp {
65 };
66 
67 typedef struct CurvesContext {
68  const AVClass *class;
69  int preset;
72  uint16_t *graph[NB_COMP + 1];
73  int lut_size;
74  char *psfile;
75  uint8_t rgba_map[4];
76  int step;
79  int is_16bit;
80  int depth;
82  int interp;
83 
84  int (*filter_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
86 
87 typedef struct ThreadData {
88  AVFrame *in, *out;
89 } ThreadData;
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
93 static const AVOption curves_options[] = {
94  { "preset", "select a color curves preset", OFFSET(preset), AV_OPT_TYPE_INT, {.i64=PRESET_NONE}, PRESET_NONE, NB_PRESETS-1, FLAGS, "preset_name" },
95  { "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_NONE}, 0, 0, FLAGS, "preset_name" },
96  { "color_negative", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_COLOR_NEGATIVE}, 0, 0, FLAGS, "preset_name" },
97  { "cross_process", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_CROSS_PROCESS}, 0, 0, FLAGS, "preset_name" },
98  { "darker", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_DARKER}, 0, 0, FLAGS, "preset_name" },
99  { "increase_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_INCREASE_CONTRAST}, 0, 0, FLAGS, "preset_name" },
100  { "lighter", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_LIGHTER}, 0, 0, FLAGS, "preset_name" },
101  { "linear_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_LINEAR_CONTRAST}, 0, 0, FLAGS, "preset_name" },
102  { "medium_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_MEDIUM_CONTRAST}, 0, 0, FLAGS, "preset_name" },
103  { "negative", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_NEGATIVE}, 0, 0, FLAGS, "preset_name" },
104  { "strong_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_STRONG_CONTRAST}, 0, 0, FLAGS, "preset_name" },
105  { "vintage", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_VINTAGE}, 0, 0, FLAGS, "preset_name" },
106  { "master","set master points coordinates",OFFSET(comp_points_str[NB_COMP]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
107  { "m", "set master points coordinates",OFFSET(comp_points_str[NB_COMP]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
108  { "red", "set red points coordinates", OFFSET(comp_points_str[0]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
109  { "r", "set red points coordinates", OFFSET(comp_points_str[0]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
110  { "green", "set green points coordinates", OFFSET(comp_points_str[1]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
111  { "g", "set green points coordinates", OFFSET(comp_points_str[1]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
112  { "blue", "set blue points coordinates", OFFSET(comp_points_str[2]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
113  { "b", "set blue points coordinates", OFFSET(comp_points_str[2]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
114  { "all", "set points coordinates for all components", OFFSET(comp_points_str_all), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
115  { "psfile", "set Photoshop curves file name", OFFSET(psfile), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
116  { "plot", "save Gnuplot script of the curves in specified file", OFFSET(plot_filename), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
117  { "interp", "specify the kind of interpolation", OFFSET(interp), AV_OPT_TYPE_INT, {.i64=INTERP_NATURAL}, INTERP_NATURAL, NB_INTERPS-1, FLAGS, "interp_name" },
118  { "natural", "natural cubic spline", 0, AV_OPT_TYPE_CONST, {.i64=INTERP_NATURAL}, 0, 0, FLAGS, "interp_name" },
119  { "pchip", "monotonically cubic interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERP_PCHIP}, 0, 0, FLAGS, "interp_name" },
120  { NULL }
121 };
122 
124 
125 static const struct {
126  const char *r;
127  const char *g;
128  const char *b;
129  const char *master;
130 } curves_presets[] = {
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  },
141  [PRESET_DARKER] = { .master = "0/0 0.5/0.4 1/1" },
142  [PRESET_INCREASE_CONTRAST] = { .master = "0/0 0.149/0.066 0.831/0.905 0.905/0.98 1/1" },
143  [PRESET_LIGHTER] = { .master = "0/0 0.4/0.5 1/1" },
144  [PRESET_LINEAR_CONTRAST] = { .master = "0/0 0.305/0.286 0.694/0.713 1/1" },
145  [PRESET_MEDIUM_CONTRAST] = { .master = "0/0 0.286/0.219 0.639/0.643 1/1" },
146  [PRESET_NEGATIVE] = { .master = "0/1 1/0" },
147  [PRESET_STRONG_CONTRAST] = { .master = "0/0 0.301/0.196 0.592/0.6 0.686/0.737 1/1" },
148  [PRESET_VINTAGE] = {
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 
155 static struct keypoint *make_point(double x, double y, struct keypoint *next)
156 {
157  struct keypoint *point = av_mallocz(sizeof(*point));
158 
159  if (!point)
160  return NULL;
161  point->x = x;
162  point->y = y;
163  point->next = next;
164  return point;
165 }
166 
167 static int parse_points_str(AVFilterContext *ctx, struct keypoint **points, const char *s,
168  int lut_size)
169 {
170  char *p = (char *)s; // strtod won't alter the string
171  struct keypoint *last = NULL;
172  const int scale = lut_size - 1;
173 
174  /* construct a linked list based on the key points string */
175  while (p && *p) {
176  struct keypoint *point = make_point(0, 0, NULL);
177  if (!point)
178  return AVERROR(ENOMEM);
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) {
182  av_log(ctx, AV_LOG_ERROR, "Invalid key point coordinates (%f;%f), "
183  "x and y must be in the [0;1] range.\n", point->x, point->y);
184  return AVERROR(EINVAL);
185  }
186  if (!*points)
187  *points = point;
188  if (last) {
189  if ((int)(last->x * scale) >= (int)(point->x * scale)) {
190  av_log(ctx, AV_LOG_ERROR, "Key point coordinates (%f;%f) "
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);
194  return AVERROR(EINVAL);
195  }
196  last->next = point;
197  }
198  last = point;
199  }
200 
201  if (*points && !(*points)->next) {
202  av_log(ctx, AV_LOG_WARNING, "Only one point (at (%f;%f)) is defined, "
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 
211 static int get_nb_points(const struct keypoint *d)
212 {
213  int n = 0;
214  while (d) {
215  n++;
216  d = d->next;
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 
229 static inline int interpolate(void *log_ctx, uint16_t *y,
230  const struct keypoint *points, int nbits)
231 {
232  int i, ret = 0;
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 
238  double (*matrix)[3];
239  double *h, *r;
240  const int n = get_nb_points(points); // number of splines
241 
242  if (n == 0) {
243  for (i = 0; i < lut_size; i++)
244  y[i] = i;
245  return 0;
246  }
247 
248  if (n == 1) {
249  for (i = 0; i < lut_size; i++)
250  y[i] = CLIP(point->y * scale);
251  return 0;
252  }
253 
254  matrix = av_calloc(n, sizeof(*matrix));
255  h = av_malloc((n - 1) * sizeof(*h));
256  r = av_calloc(n, sizeof(*r));
257 
258  if (!matrix || !h || !r) {
259  ret = AVERROR(ENOMEM);
260  goto end;
261  }
262 
263  /* h(i) = x(i+1) - x(i) */
264  i = -1;
265  for (point = points; point; point = point->next) {
266  if (i != -1)
267  h[i] = point->x - xprev;
268  xprev = point->x;
269  i++;
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;
277  const double yn = point->next->next->y;
278  r[i] = 6 * ((yn-yc)/h[i] - (yc-yp)/h[i-1]);
279  point = point->next;
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. */
287  matrix[0][MD] = matrix[n - 1][MD] = 1;
288  for (i = 1; i < n - 1; i++) {
289  matrix[i][BD] = h[i-1];
290  matrix[i][MD] = 2 * (h[i-1] + h[i]);
291  matrix[i][AD] = h[i];
292  }
293 
294  /* tridiagonal solving of the linear system */
295  for (i = 1; i < n; i++) {
296  const double den = matrix[i][MD] - matrix[i][BD] * matrix[i-1][AD];
297  const double k = den ? 1./den : 1.;
298  matrix[i][AD] *= k;
299  r[i] = (r[i] - matrix[i][BD] * r[i - 1]) * k;
300  }
301  for (i = n - 2; i >= 0; i--)
302  r[i] = r[i] - matrix[i][AD] * r[i + 1];
303 
304  point = points;
305 
306  /* left padding */
307  for (i = 0; i < (int)(point->x * scale); i++)
308  y[i] = CLIP(point->y * scale);
309 
310  /* compute the graph with x=[x0..xN] */
311  i = 0;
312  av_assert0(point->next); // always at least 2 key points
313  while (point->next) {
314  const double yc = point->y;
315  const double yn = point->next->y;
316 
317  const double a = yc;
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 
322  int x;
323  const int x_start = point->x * scale;
324  const int x_end = point->next->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;
332  y[x] = CLIP(yy * scale);
333  av_log(log_ctx, AV_LOG_DEBUG, "f(%f)=%f -> y[%d]=%d\n", xx, yy, x, y[x]);
334  }
335 
336  point = point->next;
337  i++;
338  }
339 
340  /* right padding */
341  for (i = (int)(point->x * scale); i < lut_size; i++)
342  y[i] = CLIP(point->y * scale);
343 
344 end:
345  av_free(matrix);
346  av_free(h);
347  av_free(r);
348  return ret;
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 */
368 static double pchip_edge_case(double h0, double h1, double m0, double m1)
369 {
370  int mask, mask2;
371  double d;
372 
373  d = ((2 * h0 + h1) * m0 - h0 * m1) / (h0 + h1);
374 
375  mask = SIGN(d) != SIGN(m0);
376  mask2 = (SIGN(m0) != SIGN(m1)) && (fabs(d) > 3. * fabs(m0));
377 
378  if (mask) d = 0.0;
379  else if (mask2) d = 3.0 * m0;
380 
381  return d;
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 
397 static int pchip_find_derivatives(const int n, const double *hk, const double *mk, double *dk)
398 {
399  int ret = 0;
400  const int m = n - 1;
401  int8_t *smk;
402 
403  smk = av_malloc(n);
404  if (!smk) {
405  ret = AVERROR(ENOMEM);
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) {
416  dk[i + 1] = 0.0;
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 
424  dk[0] = pchip_edge_case(hk[0], hk[1], mk[0], mk[1]);
425  dk[n] = pchip_edge_case(hk[n - 1], hk[n - 2], mk[n - 1], mk[n - 2]);
426 
427 end:
428  av_free(smk);
429 
430  return ret;
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 */
441 static inline double interp_cubic_hermite_half(const double x, const double f,
442  const double d)
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 */
462 static inline int interpolate_pchip(void *log_ctx, uint16_t *y,
463  const struct keypoint *points, int nbits)
464 {
465  const struct keypoint *point = points;
466  const int lut_size = 1<<nbits;
467  const int n = get_nb_points(points); // number of endpoints
468  double *xi, *fi, *di, *hi, *mi;
469  const int scale = lut_size - 1; // white value
470  uint16_t x; /* input index/value */
471  int ret = 0;
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 */
482  const uint16_t yval = CLIP(point->y * scale);
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 */
488  if (!xi) {
489  ret = AVERROR(ENOMEM);
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++) {
500  xi[i] = point->x * scale;
501  fi[i] = point->y * scale;
502  point = point->next;
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++) {
507  const double val = (xi[i+1]-xi[i]);
508  hi[i] = val;
509  mi[i] = (fi[i+1]-fi[i]) / val;
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*/
520  ret = pchip_find_derivatives(n-1, hi, mi, di);
521  if (ret)
522  goto end;
523 
524  /* interpolate/extrapolate */
525  x = 0;
526  if (xi[0] > 0) {
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++) {
532  y[x] = yval;
533  av_log(log_ctx, AV_LOG_TRACE, "f(%f)=%f -> y[%d]=%d\n", xi0, yi0, x, y[x]);
534  }
535  av_log(log_ctx, AV_LOG_DEBUG, "Interval -1: [0, %d] -> %d\n", x - 1, yval);
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 */
551  const double yy = interp_cubic_hermite_half(1 - xx, f0, -h * d0)
552  + interp_cubic_hermite_half(xx, f1, h * d1);
553  y[x] = CLIP(yy);
554  av_log(log_ctx, AV_LOG_TRACE, "f(%f)=%f -> y[%d]=%d\n", xx, yy, x, y[x]);
555  }
556 
557  if (x > x0)
558  av_log(log_ctx, AV_LOG_DEBUG, "Interval %d: [%d, %d] -> [%d, %d]\n",
559  i, x0, x-1, y[x0], y[x-1]);
560  else
561  av_log(log_ctx, AV_LOG_DEBUG, "Interval %d: empty\n", i);
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);
569  av_log(log_ctx, AV_LOG_DEBUG, "Interval %d: [%d, %d] -> %d\n",
570  n-1, x, lut_size - 1, yval);
571  for (; x && x < lut_size; x++) { /* loop until int overflow */
572  y[x] = yval;
573  av_log(log_ctx, AV_LOG_TRACE, "f(%f)=%f -> y[%d]=%d\n", xi1, yi1, x, yval);
574  }
575  }
576 
577 end:
578  av_free(xi);
579  return ret;
580 }
581 
582 
583 static int parse_psfile(AVFilterContext *ctx, const char *fname)
584 {
585  CurvesContext *curves = ctx->priv;
586  uint8_t *buf;
587  size_t size;
588  int i, ret, av_unused(version), nb_curves;
589  AVBPrint ptstr;
590  static const int comp_ids[] = {3, 0, 1, 2};
591 
593 
594  ret = av_file_map(fname, &buf, &size, 0, NULL);
595  if (ret < 0)
596  return ret;
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 
608  READ16(version);
609  READ16(nb_curves);
610  for (i = 0; i < FFMIN(nb_curves, FF_ARRAY_ELEMS(comp_ids)); i++) {
611  int nb_points, n;
612  av_bprint_clear(&ptstr);
613  READ16(nb_points);
614  for (n = 0; n < nb_points; n++) {
615  int y, x;
616  READ16(y);
617  READ16(x);
618  av_bprintf(&ptstr, "%f/%f ", x / 255., y / 255.);
619  }
620  if (*ptstr.str) {
621  char **pts = &curves->comp_points_str[comp_ids[i]];
622  if (!*pts) {
623  *pts = av_strdup(ptstr.str);
624  av_log(ctx, AV_LOG_DEBUG, "curves %d (intid=%d) [%d points]: [%s]\n",
625  i, comp_ids[i], nb_points, *pts);
626  if (!*pts) {
627  ret = AVERROR(ENOMEM);
628  goto end;
629  }
630  }
631  }
632  }
633 end:
634  av_bprint_finalize(&ptstr, NULL);
635  av_file_unmap(buf, size);
636  return ret;
637 }
638 
639 static int dump_curves(const char *fname, uint16_t *graph[NB_COMP + 1],
640  struct keypoint *comp_points[NB_COMP + 1],
641  int lut_size)
642 {
643  int i;
644  AVBPrint buf;
645  const double scale = 1. / (lut_size - 1);
646  static const char * const colors[] = { "red", "green", "blue", "#404040", };
647  FILE *f = avpriv_fopen_utf8(fname, "w");
648 
649  av_assert0(FF_ARRAY_ELEMS(colors) == NB_COMP + 1);
650 
651  if (!f) {
652  int ret = AVERROR(errno);
653  av_log(NULL, AV_LOG_ERROR, "Cannot open file '%s' for writing: %s\n",
654  fname, av_err2str(ret));
655  return ret;
656  }
657 
659 
660  av_bprintf(&buf, "set xtics 0.1\n");
661  av_bprintf(&buf, "set ytics 0.1\n");
662  av_bprintf(&buf, "set size square\n");
663  av_bprintf(&buf, "set grid\n");
664 
665  for (i = 0; i < FF_ARRAY_ELEMS(colors); i++) {
666  av_bprintf(&buf, "%s'-' using 1:2 with lines lc '%s' title ''",
667  i ? ", " : "plot ", colors[i]);
668  if (comp_points[i])
669  av_bprintf(&buf, ", '-' using 1:2 with points pointtype 3 lc '%s' title ''",
670  colors[i]);
671  }
672  av_bprintf(&buf, "\n");
673 
674  for (i = 0; i < FF_ARRAY_ELEMS(colors); i++) {
675  int x;
676 
677  /* plot generated values */
678  for (x = 0; x < lut_size; x++)
679  av_bprintf(&buf, "%f %f\n", x * scale, graph[i][x] * scale);
680  av_bprintf(&buf, "e\n");
681 
682  /* plot user knots */
683  if (comp_points[i]) {
684  const struct keypoint *point = comp_points[i];
685 
686  while (point) {
687  av_bprintf(&buf, "%f %f\n", point->x, point->y);
688  point = point->next;
689  }
690  av_bprintf(&buf, "e\n");
691  }
692  }
693 
694  fwrite(buf.str, 1, buf.len, f);
695  fclose(f);
696  av_bprint_finalize(&buf, NULL);
697  return 0;
698 }
699 
701 {
702  int i, ret;
703  CurvesContext *curves = ctx->priv;
704  char **pts = curves->comp_points_str;
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) {
711  for (i = 0; i < NB_COMP; i++) {
712  if (!pts[i])
713  pts[i] = av_strdup(allp);
714  if (!pts[i])
715  return AVERROR(ENOMEM);
716  }
717  }
718 
719  if (curves->psfile && !curves->parsed_psfile) {
720  ret = parse_psfile(ctx, curves->psfile);
721  if (ret < 0)
722  return ret;
723  curves->parsed_psfile = 1;
724  }
725 
726  if (curves->preset != PRESET_NONE) {
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)
738  curves->preset = PRESET_NONE;
739  }
740 
741  return 0;
742 }
743 
744 static int filter_slice_packed(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
745 {
746  int x, y;
747  const CurvesContext *curves = ctx->priv;
748  const ThreadData *td = arg;
749  const AVFrame *in = td->in;
750  const AVFrame *out = td->out;
751  const int direct = out == in;
752  const int step = curves->step;
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];
757  const int slice_start = (in->height * jobnr ) / nb_jobs;
758  const int slice_end = (in->height * (jobnr+1)) / nb_jobs;
759 
760  if (curves->is_16bit) {
761  for (y = slice_start; y < slice_end; y++) {
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 
765  for (x = 0; x < in->width * step; x += step) {
766  dstp[x + r] = curves->graph[R][srcp[x + r]];
767  dstp[x + g] = curves->graph[G][srcp[x + g]];
768  dstp[x + b] = curves->graph[B][srcp[x + b]];
769  if (!direct && step == 4)
770  dstp[x + a] = srcp[x + a];
771  }
772  }
773  } else {
774  uint8_t *dst = out->data[0] + slice_start * out->linesize[0];
775  const uint8_t *src = in->data[0] + slice_start * in->linesize[0];
776 
777  for (y = slice_start; y < slice_end; y++) {
778  for (x = 0; x < in->width * step; x += step) {
779  dst[x + r] = curves->graph[R][src[x + r]];
780  dst[x + g] = curves->graph[G][src[x + g]];
781  dst[x + b] = curves->graph[B][src[x + b]];
782  if (!direct && step == 4)
783  dst[x + a] = src[x + a];
784  }
785  dst += out->linesize[0];
786  src += in ->linesize[0];
787  }
788  }
789  return 0;
790 }
791 
792 static int filter_slice_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
793 {
794  int x, y;
795  const CurvesContext *curves = ctx->priv;
796  const ThreadData *td = arg;
797  const AVFrame *in = td->in;
798  const AVFrame *out = td->out;
799  const int direct = out == in;
800  const int step = curves->step;
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];
805  const int slice_start = (in->height * jobnr ) / nb_jobs;
806  const int slice_end = (in->height * (jobnr+1)) / nb_jobs;
807 
808  if (curves->is_16bit) {
809  for (y = slice_start; y < slice_end; y++) {
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 
819  for (x = 0; x < in->width; x++) {
820  dstrp[x] = curves->graph[R][srcrp[x]];
821  dstgp[x] = curves->graph[G][srcgp[x]];
822  dstbp[x] = curves->graph[B][srcbp[x]];
823  if (!direct && step == 4)
824  dstap[x] = srcap[x];
825  }
826  }
827  } else {
828  uint8_t *dstr = out->data[r] + slice_start * out->linesize[r];
829  uint8_t *dstg = out->data[g] + slice_start * out->linesize[g];
830  uint8_t *dstb = out->data[b] + slice_start * out->linesize[b];
831  uint8_t *dsta = out->data[a] + slice_start * out->linesize[a];
832  const uint8_t *srcr = in->data[r] + slice_start * in->linesize[r];
833  const uint8_t *srcg = in->data[g] + slice_start * in->linesize[g];
834  const uint8_t *srcb = in->data[b] + slice_start * in->linesize[b];
835  const uint8_t *srca = in->data[a] + slice_start * in->linesize[a];
836 
837  for (y = slice_start; y < slice_end; y++) {
838  for (x = 0; x < in->width; x++) {
839  dstr[x] = curves->graph[R][srcr[x]];
840  dstg[x] = curves->graph[G][srcg[x]];
841  dstb[x] = curves->graph[B][srcb[x]];
842  if (!direct && step == 4)
843  dsta[x] = srca[x];
844  }
845  dstr += out->linesize[r];
846  dstg += out->linesize[g];
847  dstb += out->linesize[b];
848  dsta += out->linesize[a];
849  srcr += in ->linesize[r];
850  srcg += in ->linesize[g];
851  srcb += in ->linesize[b];
852  srca += in ->linesize[a];
853  }
854  }
855  return 0;
856 }
857 
859 {
860  int i, j, ret;
861  AVFilterContext *ctx = inlink->dst;
862  CurvesContext *curves = ctx->priv;
864  char **pts = curves->comp_points_str;
865  struct keypoint *comp_points[NB_COMP + 1] = {0};
866 
867  ff_fill_rgba_map(curves->rgba_map, inlink->format);
868  curves->is_16bit = desc->comp[0].depth > 8;
869  curves->depth = desc->comp[0].depth;
870  curves->lut_size = 1 << curves->depth;
871  curves->step = av_get_padded_bits_per_pixel(desc) >> (3 + curves->is_16bit);
873 
874  for (i = 0; i < NB_COMP + 1; i++) {
875  if (!curves->graph[i])
876  curves->graph[i] = av_calloc(curves->lut_size, sizeof(*curves->graph[0]));
877  if (!curves->graph[i])
878  return AVERROR(ENOMEM);
879  ret = parse_points_str(ctx, comp_points + i, curves->comp_points_str[i], curves->lut_size);
880  if (ret < 0)
881  return ret;
882  if (curves->interp == INTERP_PCHIP)
883  ret = interpolate_pchip(ctx, curves->graph[i], comp_points[i], curves->depth);
884  else
885  ret = interpolate(ctx, curves->graph[i], comp_points[i], curves->depth);
886  if (ret < 0)
887  return ret;
888  }
889 
890  if (pts[NB_COMP]) {
891  for (i = 0; i < NB_COMP; i++)
892  for (j = 0; j < curves->lut_size; j++)
893  curves->graph[i][j] = curves->graph[NB_COMP][curves->graph[i][j]];
894  }
895 
896  if (av_log_get_level() >= AV_LOG_VERBOSE) {
897  for (i = 0; i < NB_COMP; i++) {
898  const struct keypoint *point = comp_points[i];
899  av_log(ctx, AV_LOG_VERBOSE, "#%d points:", i);
900  while (point) {
901  av_log(ctx, AV_LOG_VERBOSE, " (%f;%f)", point->x, point->y);
902  point = point->next;
903  }
904  }
905  }
906 
907  if (curves->plot_filename && !curves->saved_plot) {
908  dump_curves(curves->plot_filename, curves->graph, comp_points, curves->lut_size);
909  curves->saved_plot = 1;
910  }
911 
912  for (i = 0; i < NB_COMP + 1; i++) {
913  struct keypoint *point = comp_points[i];
914  while (point) {
915  struct keypoint *next = point->next;
916  av_free(point);
917  point = next;
918  }
919  }
920 
921  return 0;
922 }
923 
925 {
926  AVFilterContext *ctx = inlink->dst;
927  CurvesContext *curves = ctx->priv;
928  AVFilterLink *outlink = ctx->outputs[0];
929  AVFrame *out;
930  ThreadData td;
931 
932  if (av_frame_is_writable(in)) {
933  out = in;
934  } else {
935  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
936  if (!out) {
937  av_frame_free(&in);
938  return AVERROR(ENOMEM);
939  }
941  }
942 
943  td.in = in;
944  td.out = out;
945  ff_filter_execute(ctx, curves->filter_slice, &td, NULL,
946  FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
947 
948  if (out != in)
949  av_frame_free(&in);
950 
951  return ff_filter_frame(outlink, out);
952 }
953 
954 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
955  char *res, int res_len, int flags)
956 {
957  CurvesContext *curves = ctx->priv;
958  int ret;
959 
960  if (!strcmp(cmd, "plot")) {
961  curves->saved_plot = 0;
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;
965  av_freep(&curves->comp_points_str_all);
966  av_freep(&curves->comp_points_str[0]);
967  av_freep(&curves->comp_points_str[1]);
968  av_freep(&curves->comp_points_str[2]);
969  av_freep(&curves->comp_points_str[NB_COMP]);
970  } else if (!strcmp(cmd, "red") || !strcmp(cmd, "r")) {
971  av_freep(&curves->comp_points_str[0]);
972  } else if (!strcmp(cmd, "green") || !strcmp(cmd, "g")) {
973  av_freep(&curves->comp_points_str[1]);
974  } else if (!strcmp(cmd, "blue") || !strcmp(cmd, "b")) {
975  av_freep(&curves->comp_points_str[2]);
976  } else if (!strcmp(cmd, "master") || !strcmp(cmd, "m")) {
977  av_freep(&curves->comp_points_str[NB_COMP]);
978  }
979 
980  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
981  if (ret < 0)
982  return ret;
983 
984  ret = curves_init(ctx);
985  if (ret < 0)
986  return ret;
987  return config_input(ctx->inputs[0]);
988 }
989 
991 {
992  int i;
993  CurvesContext *curves = ctx->priv;
994 
995  for (i = 0; i < NB_COMP + 1; i++)
996  av_freep(&curves->graph[i]);
997 }
998 
999 static const AVFilterPad curves_inputs[] = {
1000  {
1001  .name = "default",
1002  .type = AVMEDIA_TYPE_VIDEO,
1003  .filter_frame = filter_frame,
1004  .config_props = config_input,
1005  },
1006 };
1007 
1008 static const AVFilterPad curves_outputs[] = {
1009  {
1010  .name = "default",
1011  .type = AVMEDIA_TYPE_VIDEO,
1012  },
1013 };
1014 
1016  .name = "curves",
1017  .description = NULL_IF_CONFIG_SMALL("Adjust components curves."),
1018  .priv_size = sizeof(CurvesContext),
1019  .init = curves_init,
1020  .uninit = curves_uninit,
1036  .priv_class = &curves_class,
1038  .process_command = process_command,
1039 };
ff_get_video_buffer
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:101
AV_PIX_FMT_GBRAP16
#define AV_PIX_FMT_GBRAP16
Definition: pixfmt.h:481
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
h0
static const float h0[64]
Definition: speexdata.h:741
CurvesContext::graph
uint16_t * graph[NB_COMP+1]
Definition: vf_curves.c:72
td
#define td
Definition: regdef.h:70
PRESET_CROSS_PROCESS
@ PRESET_CROSS_PROCESS
Definition: vf_curves.c:49
READ16
#define READ16(dst)
PRESET_LIGHTER
@ PRESET_LIGHTER
Definition: vf_curves.c:52
r
const char * r
Definition: vf_curves.c:126
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
CurvesContext::psfile
char * psfile
Definition: vf_curves.c:74
dump_curves
static int dump_curves(const char *fname, uint16_t *graph[NB_COMP+1], struct keypoint *comp_points[NB_COMP+1], int lut_size)
Definition: vf_curves.c:639
interp_cubic_hermite_half
static double interp_cubic_hermite_half(const double x, const double f, const double d)
Evalaute half of the cubic hermite interpolation expression, wrt one interval endpoint.
Definition: vf_curves.c:441
out
FILE * out
Definition: movenc.c:54
curves
static const Curve curves[]
Definition: vf_pseudocolor.c:140
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
keypoint::next
struct keypoint * next
Definition: vf_curves.c:41
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:969
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2888
matrix
Definition: vc1dsp.c:42
inlink
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
Definition: filter_design.txt:212
FLAGS
#define FLAGS
Definition: vf_curves.c:92
CurvesContext::saved_plot
int saved_plot
Definition: vf_curves.c:78
PRESET_MEDIUM_CONTRAST
@ PRESET_MEDIUM_CONTRAST
Definition: vf_curves.c:54
av_unused
#define av_unused
Definition: attributes.h:131
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:99
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:330
pixdesc.h
step
trying all byte sequences megabyte in length and selecting the best looking sequence will yield cases to try But a word about which is also called distortion Distortion can be quantified by almost any quality measurement one chooses the sum of squared differences is used but more complex methods that consider psychovisual effects can be used as well It makes no difference in this discussion First step
Definition: rate_distortion.txt:58
AVFrame::width
int width
Definition: frame.h:402
AVOption
AVOption.
Definition: opt.h:251
data
const char data[16]
Definition: mxf.c:146
CurvesContext
Definition: vf_curves.c:67
curves_inputs
static const AVFilterPad curves_inputs[]
Definition: vf_curves.c:999
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:196
AV_PIX_FMT_BGR24
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
AV_PIX_FMT_BGRA
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:165
BD
#define BD
ThreadData::out
AVFrame * out
Definition: af_adeclick.c:473
get_nb_points
static int get_nb_points(const struct keypoint *d)
Definition: vf_curves.c:211
CurvesContext::rgba_map
uint8_t rgba_map[4]
Definition: vf_curves.c:75
video.h
ThreadData::in
AVFrame * in
Definition: af_adecorrelate.c:154
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:351
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:30
CurvesContext::filter_slice
int(* filter_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_curves.c:84
A
#define A
Definition: vf_curves.c:37
AV_PIX_FMT_GBRP14
#define AV_PIX_FMT_GBRP14
Definition: pixfmt.h:477
av_file_map
int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, int log_offset, void *log_ctx)
Read the file with name filename, and put its content in a newly allocated buffer or map it with mmap...
Definition: file.c:54
AV_PIX_FMT_GBRAP
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
Definition: pixfmt.h:205
interp
interp
Definition: vf_curves.c:61
AV_PIX_FMT_GBRP10
#define AV_PIX_FMT_GBRP10
Definition: pixfmt.h:475
NB_PRESETS
@ NB_PRESETS
Definition: vf_curves.c:58
CurvesContext::preset
int preset
Definition: vf_curves.c:69
AV_BPRINT_SIZE_AUTOMATIC
#define AV_BPRINT_SIZE_AUTOMATIC
val
static double val(void *priv, double ch)
Definition: aeval.c:77
scale
static av_always_inline float scale(float x, float s)
Definition: vf_v360.c:1389
pts
static int64_t pts
Definition: transcode_aac.c:653
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:49
preset
preset
Definition: vf_curves.c:46
avassert.h
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:206
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
av_cold
#define av_cold
Definition: attributes.h:90
mask
static const uint16_t mask[17]
Definition: lzw.c:38
AV_PIX_FMT_GBRAP10
#define AV_PIX_FMT_GBRAP10
Definition: pixfmt.h:479
keypoint::x
double x
Definition: vf_curves.c:40
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:256
AV_PIX_FMT_GBRAP12
#define AV_PIX_FMT_GBRAP12
Definition: pixfmt.h:480
process_command
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: vf_curves.c:954
mi
#define mi
Definition: vf_colormatrix.c:108
g
const char * g
Definition: vf_curves.c:127
curves_outputs
static const AVFilterPad curves_outputs[]
Definition: vf_curves.c:1008
keypoint
Definition: vf_curves.c:39
slice_end
static int slice_end(AVCodecContext *avctx, AVFrame *pict)
Handle slice ends.
Definition: mpeg12dec.c:2006
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts_bsf.c:365
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
CLIP
#define CLIP(v)
Natural cubic spline interpolation Finding curves using Cubic Splines notes by Steven Rauch and John ...
Definition: vf_curves.c:227
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(curves)
ctx
AVFormatContext * ctx
Definition: movenc.c:48
xi
#define xi(width, name, var, range_min, range_max, subs,...)
Definition: cbs_h2645.c:402
CurvesContext::lut_size
int lut_size
Definition: vf_curves.c:73
CurvesContext::is_16bit
int is_16bit
Definition: vf_curves.c:79
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: internal.h:194
file_open.h
av_file_unmap
void av_file_unmap(uint8_t *bufptr, size_t size)
Unmap or free the buffer bufptr created by av_file_map().
Definition: file.c:145
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
arg
const char * arg
Definition: jacosubdec.c:67
av_log_get_level
int av_log_get_level(void)
Get the current log level.
Definition: log.c:437
AV_PIX_FMT_GBRP16
#define AV_PIX_FMT_GBRP16
Definition: pixfmt.h:478
AV_PIX_FMT_RGBA64
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:449
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
interpolate
static int interpolate(void *log_ctx, uint16_t *y, const struct keypoint *points, int nbits)
Definition: vf_curves.c:229
fabs
static __device__ float fabs(float a)
Definition: cuda_runtime.h:182
AV_PIX_FMT_BGR48
#define AV_PIX_FMT_BGR48
Definition: pixfmt.h:450
NULL
#define NULL
Definition: coverity.c:32
av_frame_copy_props
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:594
G
#define G
Definition: vf_curves.c:35
INTERP_PCHIP
@ INTERP_PCHIP
Definition: vf_curves.c:63
CurvesContext::parsed_psfile
int parsed_psfile
Definition: vf_curves.c:81
double
double
Definition: af_crystalizer.c:132
AV_PIX_FMT_BGR0
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:258
CurvesContext::depth
int depth
Definition: vf_curves.c:80
AV_PIX_FMT_GBRP9
#define AV_PIX_FMT_GBRP9
Definition: pixfmt.h:474
AV_PIX_FMT_ABGR
@ AV_PIX_FMT_ABGR
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
Definition: pixfmt.h:94
MD
#define MD
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
b
const char * b
Definition: vf_curves.c:128
CurvesContext::interp
int interp
Definition: vf_curves.c:82
PRESET_DARKER
@ PRESET_DARKER
Definition: vf_curves.c:50
eval.h
AD
#define AD
f
f
Definition: af_crystalizer.c:122
AV_PIX_FMT_RGB24
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:115
master
const char * master
Definition: vf_curves.c:129
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
av_get_padded_bits_per_pixel
int av_get_padded_bits_per_pixel(const AVPixFmtDescriptor *pixdesc)
Return the number of bits per pixel for the pixel format described by pixdesc, including any padding ...
Definition: pixdesc.c:2853
FILTER_PIXFMTS
#define FILTER_PIXFMTS(...)
Definition: internal.h:180
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:121
ff_vf_curves
const AVFilter ff_vf_curves
Definition: vf_curves.c:1015
AV_PIX_FMT_RGB48
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:445
size
int size
Definition: twinvq_data.h:10344
curves_uninit
static av_cold void curves_uninit(AVFilterContext *ctx)
Definition: vf_curves.c:990
av_frame_is_writable
int av_frame_is_writable(AVFrame *frame)
Check if the frame data is writable.
Definition: frame.c:524
filter_slice_planar
static int filter_slice_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_curves.c:792
INTERP_NATURAL
@ INTERP_NATURAL
Definition: vf_curves.c:62
NB_INTERPS
@ NB_INTERPS
Definition: vf_curves.c:64
ff_filter_process_command
int ff_filter_process_command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Generic processing of user supplied commands that are set in the same way as the filter options.
Definition: avfilter.c:842
curves_options
static const AVOption curves_options[]
Definition: vf_curves.c:93
a
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:41
AV_PIX_FMT_RGB0
@ AV_PIX_FMT_RGB0
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:256
version
version
Definition: libkvazaar.c:313
filter_slice_packed
static int filter_slice_packed(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_curves.c:744
CurvesContext::plot_filename
char * plot_filename
Definition: vf_curves.c:77
SIGN
#define SIGN(x)
Definition: vf_curves.c:352
internal.h
AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
Some filters support a generic "enable" expression option that can be used to enable or disable a fil...
Definition: avfilter.h:142
AV_PIX_FMT_ARGB
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition: pixfmt.h:92
CurvesContext::comp_points_str
char * comp_points_str[NB_COMP+1]
Definition: vf_curves.c:70
PRESET_INCREASE_CONTRAST
@ PRESET_INCREASE_CONTRAST
Definition: vf_curves.c:51
AV_PIX_FMT_BGRA64
#define AV_PIX_FMT_BGRA64
Definition: pixfmt.h:454
bprint.h
curves_presets
static const struct @239 curves_presets[]
PRESET_NONE
@ PRESET_NONE
Definition: vf_curves.c:47
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
B
#define B
Definition: vf_curves.c:36
CurvesContext::step
int step
Definition: vf_curves.c:76
AV_PIX_FMT_GBRP12
#define AV_PIX_FMT_GBRP12
Definition: pixfmt.h:476
ff_filter_get_nb_threads
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:777
ThreadData
Used for passing data between threads.
Definition: dsddec.c:69
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:254
PRESET_VINTAGE
@ PRESET_VINTAGE
Definition: vf_curves.c:57
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:55
avpriv_fopen_utf8
FILE * avpriv_fopen_utf8(const char *path, const char *mode)
Open a file using a UTF-8 filename.
Definition: file_open.c:159
PRESET_COLOR_NEGATIVE
@ PRESET_COLOR_NEGATIVE
Definition: vf_curves.c:48
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:262
AVFilter
Filter definition.
Definition: avfilter.h:161
NB_COMP
#define NB_COMP
Definition: vf_curves.c:44
ret
ret
Definition: filter_design.txt:187
AV_PIX_FMT_0BGR
@ AV_PIX_FMT_0BGR
packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined
Definition: pixfmt.h:257
av_strtod
double av_strtod(const char *numstr, char **tail)
Parse the string in numstr and return its value as a double.
Definition: eval.c:106
R
#define R
Definition: vf_curves.c:34
CurvesContext::comp_points_str_all
char * comp_points_str_all
Definition: vf_curves.c:71
PRESET_NEGATIVE
@ PRESET_NEGATIVE
Definition: vf_curves.c:55
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:94
AVFrame::height
int height
Definition: frame.h:402
PRESET_LINEAR_CONTRAST
@ PRESET_LINEAR_CONTRAST
Definition: vf_curves.c:53
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:225
avfilter.h
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
pchip_find_derivatives
static int pchip_find_derivatives(const int n, const double *hk, const double *mk, double *dk)
Evalaute the piecewise polynomial derivatives at endpoints.
Definition: vf_curves.c:397
make_point
static struct keypoint * make_point(double x, double y, struct keypoint *next)
Definition: vf_curves.c:155
AV_PIX_FMT_FLAG_PLANAR
#define AV_PIX_FMT_FLAG_PLANAR
At least one pixel component is not in the first data plane.
Definition: pixdesc.h:132
config_input
static int config_input(AVFilterLink *inlink)
Definition: vf_curves.c:858
file.h
AVFilterContext
An instance of a filter.
Definition: avfilter.h:392
AV_PIX_FMT_GBRP
@ AV_PIX_FMT_GBRP
planar GBR 4:4:4 24bpp
Definition: pixfmt.h:158
AVFILTER_FLAG_SLICE_THREADS
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:117
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:270
desc
const char * desc
Definition: libsvtav1.c:83
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
SET_COMP_IF_NOT_SET
#define SET_COMP_IF_NOT_SET(n, name)
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
curves_init
static av_cold int curves_init(AVFilterContext *ctx)
Definition: vf_curves.c:700
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:195
interpolate_pchip
static int interpolate_pchip(void *log_ctx, uint16_t *y, const struct keypoint *points, int nbits)
Prepare the lookup table by piecewise monotonic cubic interpolation (PCHIP)
Definition: vf_curves.c:462
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
keypoint::y
double y
Definition: vf_curves.c:40
parse_psfile
static int parse_psfile(AVFilterContext *ctx, const char *fname)
Definition: vf_curves.c:583
parse_points_str
static int parse_points_str(AVFilterContext *ctx, struct keypoint **points, const char *s, int lut_size)
Definition: vf_curves.c:167
ff_fill_rgba_map
int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
Definition: drawutils.c:35
d
d
Definition: ffmpeg_filter.c:156
pchip_edge_case
static double pchip_edge_case(double h0, double h1, double m0, double m1)
Evalaute the derivative of an edge endpoint.
Definition: vf_curves.c:368
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition: frame.h:375
AV_PIX_FMT_0RGB
@ AV_PIX_FMT_0RGB
packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined
Definition: pixfmt.h:255
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
uninit
static av_cold int uninit(AVCodecContext *avctx)
Definition: crystalhd.c:285
h
h
Definition: vp9dsp_template.c:2038
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:229
drawutils.h
ff_filter_execute
static av_always_inline int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
Definition: internal.h:146
PRESET_STRONG_CONTRAST
@ PRESET_STRONG_CONTRAST
Definition: vf_curves.c:56
int
int
Definition: ffmpeg_filter.c:156
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:234
OFFSET
#define OFFSET(x)
Definition: vf_curves.c:91
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_curves.c:924