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/mem.h"
22 #include "libavutil/opt.h"
23 #include "libavutil/bprint.h"
24 #include "libavutil/eval.h"
25 #include "libavutil/file.h"
26 #include "libavutil/file_open.h"
27 #include "libavutil/intreadwrite.h"
28 #include "libavutil/avassert.h"
29 #include "libavutil/pixdesc.h"
30 #include "avfilter.h"
31 #include "drawutils.h"
32 #include "internal.h"
33 #include "video.h"
34 
35 #define R 0
36 #define G 1
37 #define B 2
38 #define A 3
39 
40 struct keypoint {
41  double x, y;
42  struct keypoint *next;
43 };
44 
45 #define NB_COMP 3
46 
47 enum preset {
60 };
61 
62 enum interp {
66 };
67 
68 typedef struct CurvesContext {
69  const AVClass *class;
70  int preset;
73  uint16_t *graph[NB_COMP + 1];
74  int lut_size;
75  char *psfile;
76  uint8_t rgba_map[4];
77  int step;
80  int is_16bit;
81  int depth;
83  int interp;
84 
85  int (*filter_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
87 
88 typedef struct ThreadData {
89  AVFrame *in, *out;
90 } ThreadData;
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
94 static const AVOption curves_options[] = {
95  { "preset", "select a color curves preset", OFFSET(preset), AV_OPT_TYPE_INT, {.i64=PRESET_NONE}, PRESET_NONE, NB_PRESETS-1, FLAGS, .unit = "preset_name" },
96  { "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_NONE}, 0, 0, FLAGS, .unit = "preset_name" },
97  { "color_negative", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_COLOR_NEGATIVE}, 0, 0, FLAGS, .unit = "preset_name" },
98  { "cross_process", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_CROSS_PROCESS}, 0, 0, FLAGS, .unit = "preset_name" },
99  { "darker", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_DARKER}, 0, 0, FLAGS, .unit = "preset_name" },
100  { "increase_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_INCREASE_CONTRAST}, 0, 0, FLAGS, .unit = "preset_name" },
101  { "lighter", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_LIGHTER}, 0, 0, FLAGS, .unit = "preset_name" },
102  { "linear_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_LINEAR_CONTRAST}, 0, 0, FLAGS, .unit = "preset_name" },
103  { "medium_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_MEDIUM_CONTRAST}, 0, 0, FLAGS, .unit = "preset_name" },
104  { "negative", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_NEGATIVE}, 0, 0, FLAGS, .unit = "preset_name" },
105  { "strong_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_STRONG_CONTRAST}, 0, 0, FLAGS, .unit = "preset_name" },
106  { "vintage", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_VINTAGE}, 0, 0, FLAGS, .unit = "preset_name" },
107  { "master","set master points coordinates",OFFSET(comp_points_str[NB_COMP]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
108  { "m", "set master points coordinates",OFFSET(comp_points_str[NB_COMP]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
109  { "red", "set red points coordinates", OFFSET(comp_points_str[0]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
110  { "r", "set red points coordinates", OFFSET(comp_points_str[0]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
111  { "green", "set green points coordinates", OFFSET(comp_points_str[1]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
112  { "g", "set green points coordinates", OFFSET(comp_points_str[1]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
113  { "blue", "set blue points coordinates", OFFSET(comp_points_str[2]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
114  { "b", "set blue points coordinates", OFFSET(comp_points_str[2]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
115  { "all", "set points coordinates for all components", OFFSET(comp_points_str_all), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
116  { "psfile", "set Photoshop curves file name", OFFSET(psfile), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
117  { "plot", "save Gnuplot script of the curves in specified file", OFFSET(plot_filename), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
118  { "interp", "specify the kind of interpolation", OFFSET(interp), AV_OPT_TYPE_INT, {.i64=INTERP_NATURAL}, INTERP_NATURAL, NB_INTERPS-1, FLAGS, .unit = "interp_name" },
119  { "natural", "natural cubic spline", 0, AV_OPT_TYPE_CONST, {.i64=INTERP_NATURAL}, 0, 0, FLAGS, .unit = "interp_name" },
120  { "pchip", "monotonically cubic interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERP_PCHIP}, 0, 0, FLAGS, .unit = "interp_name" },
121  { NULL }
122 };
123 
125 
126 static const struct {
127  const char *r;
128  const char *g;
129  const char *b;
130  const char *master;
131 } curves_presets[] = {
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  },
142  [PRESET_DARKER] = { .master = "0/0 0.5/0.4 1/1" },
143  [PRESET_INCREASE_CONTRAST] = { .master = "0/0 0.149/0.066 0.831/0.905 0.905/0.98 1/1" },
144  [PRESET_LIGHTER] = { .master = "0/0 0.4/0.5 1/1" },
145  [PRESET_LINEAR_CONTRAST] = { .master = "0/0 0.305/0.286 0.694/0.713 1/1" },
146  [PRESET_MEDIUM_CONTRAST] = { .master = "0/0 0.286/0.219 0.639/0.643 1/1" },
147  [PRESET_NEGATIVE] = { .master = "0/1 1/0" },
148  [PRESET_STRONG_CONTRAST] = { .master = "0/0 0.301/0.196 0.592/0.6 0.686/0.737 1/1" },
149  [PRESET_VINTAGE] = {
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 
156 static struct keypoint *make_point(double x, double y, struct keypoint *next)
157 {
158  struct keypoint *point = av_mallocz(sizeof(*point));
159 
160  if (!point)
161  return NULL;
162  point->x = x;
163  point->y = y;
164  point->next = next;
165  return point;
166 }
167 
168 static int parse_points_str(AVFilterContext *ctx, struct keypoint **points, const char *s,
169  int lut_size)
170 {
171  char *p = (char *)s; // strtod won't alter the string
172  struct keypoint *last = NULL;
173  const int scale = lut_size - 1;
174 
175  /* construct a linked list based on the key points string */
176  while (p && *p) {
177  struct keypoint *point = make_point(0, 0, NULL);
178  if (!point)
179  return AVERROR(ENOMEM);
180  point->x = av_strtod(p, &p); if (p && *p) p++;
181  point->y = av_strtod(p, &p); if (p && *p) p++;
182  if (point->x < 0 || point->x > 1 || point->y < 0 || point->y > 1) {
183  av_log(ctx, AV_LOG_ERROR, "Invalid key point coordinates (%f;%f), "
184  "x and y must be in the [0;1] range.\n", point->x, point->y);
185  return AVERROR(EINVAL);
186  }
187  if (!*points)
188  *points = point;
189  if (last) {
190  if ((int)(last->x * scale) >= (int)(point->x * scale)) {
191  av_log(ctx, AV_LOG_ERROR, "Key point coordinates (%f;%f) "
192  "and (%f;%f) are too close from each other or not "
193  "strictly increasing on the x-axis\n",
194  last->x, last->y, point->x, point->y);
195  return AVERROR(EINVAL);
196  }
197  last->next = point;
198  }
199  last = point;
200  }
201 
202  if (*points && !(*points)->next) {
203  av_log(ctx, AV_LOG_WARNING, "Only one point (at (%f;%f)) is defined, "
204  "this is unlikely to behave as you expect. You probably want"
205  "at least 2 points.",
206  (*points)->x, (*points)->y);
207  }
208 
209  return 0;
210 }
211 
212 static int get_nb_points(const struct keypoint *d)
213 {
214  int n = 0;
215  while (d) {
216  n++;
217  d = d->next;
218  }
219  return n;
220 }
221 
222 /**
223  * Natural cubic spline interpolation
224  * Finding curves using Cubic Splines notes by Steven Rauch and John Stockie.
225  * @see http://people.math.sfu.ca/~stockie/teaching/macm316/notes/splines.pdf
226  */
227 
228 #define CLIP(v) (nbits == 8 ? av_clip_uint8(v) : av_clip_uintp2_c(v, nbits))
229 
230 static inline int interpolate(void *log_ctx, uint16_t *y,
231  const struct keypoint *points, int nbits)
232 {
233  int i, ret = 0;
234  const struct keypoint *point = points;
235  double xprev = 0;
236  const int lut_size = 1<<nbits;
237  const int scale = lut_size - 1;
238 
239  double (*matrix)[3];
240  double *h, *r;
241  const int n = get_nb_points(points); // number of splines
242 
243  if (n == 0) {
244  for (i = 0; i < lut_size; i++)
245  y[i] = i;
246  return 0;
247  }
248 
249  if (n == 1) {
250  for (i = 0; i < lut_size; i++)
251  y[i] = CLIP(point->y * scale);
252  return 0;
253  }
254 
255  matrix = av_calloc(n, sizeof(*matrix));
256  h = av_malloc((n - 1) * sizeof(*h));
257  r = av_calloc(n, sizeof(*r));
258 
259  if (!matrix || !h || !r) {
260  ret = AVERROR(ENOMEM);
261  goto end;
262  }
263 
264  /* h(i) = x(i+1) - x(i) */
265  i = -1;
266  for (point = points; point; point = point->next) {
267  if (i != -1)
268  h[i] = point->x - xprev;
269  xprev = point->x;
270  i++;
271  }
272 
273  /* right-side of the polynomials, will be modified to contains the solution */
274  point = points;
275  for (i = 1; i < n - 1; i++) {
276  const double yp = point->y;
277  const double yc = point->next->y;
278  const double yn = point->next->next->y;
279  r[i] = 6 * ((yn-yc)/h[i] - (yc-yp)/h[i-1]);
280  point = point->next;
281  }
282 
283 #define BD 0 /* sub diagonal (below main) */
284 #define MD 1 /* main diagonal (center) */
285 #define AD 2 /* sup diagonal (above main) */
286 
287  /* left side of the polynomials into a tridiagonal matrix. */
288  matrix[0][MD] = matrix[n - 1][MD] = 1;
289  for (i = 1; i < n - 1; i++) {
290  matrix[i][BD] = h[i-1];
291  matrix[i][MD] = 2 * (h[i-1] + h[i]);
292  matrix[i][AD] = h[i];
293  }
294 
295  /* tridiagonal solving of the linear system */
296  for (i = 1; i < n; i++) {
297  const double den = matrix[i][MD] - matrix[i][BD] * matrix[i-1][AD];
298  const double k = den ? 1./den : 1.;
299  matrix[i][AD] *= k;
300  r[i] = (r[i] - matrix[i][BD] * r[i - 1]) * k;
301  }
302  for (i = n - 2; i >= 0; i--)
303  r[i] = r[i] - matrix[i][AD] * r[i + 1];
304 
305  point = points;
306 
307  /* left padding */
308  for (i = 0; i < (int)(point->x * scale); i++)
309  y[i] = CLIP(point->y * scale);
310 
311  /* compute the graph with x=[x0..xN] */
312  i = 0;
313  av_assert0(point->next); // always at least 2 key points
314  while (point->next) {
315  const double yc = point->y;
316  const double yn = point->next->y;
317 
318  const double a = yc;
319  const double b = (yn-yc)/h[i] - h[i]*r[i]/2. - h[i]*(r[i+1]-r[i])/6.;
320  const double c = r[i] / 2.;
321  const double d = (r[i+1] - r[i]) / (6.*h[i]);
322 
323  int x;
324  const int x_start = point->x * scale;
325  const int x_end = point->next->x * scale;
326 
327  av_assert0(x_start >= 0 && x_start < lut_size &&
328  x_end >= 0 && x_end < lut_size);
329 
330  for (x = x_start; x <= x_end; x++) {
331  const double xx = (x - x_start) * 1./scale;
332  const double yy = a + b*xx + c*xx*xx + d*xx*xx*xx;
333  y[x] = CLIP(yy * scale);
334  av_log(log_ctx, AV_LOG_DEBUG, "f(%f)=%f -> y[%d]=%d\n", xx, yy, x, y[x]);
335  }
336 
337  point = point->next;
338  i++;
339  }
340 
341  /* right padding */
342  for (i = (int)(point->x * scale); i < lut_size; i++)
343  y[i] = CLIP(point->y * scale);
344 
345 end:
346  av_free(matrix);
347  av_free(h);
348  av_free(r);
349  return ret;
350 
351 }
352 
353 #define SIGN(x) (x > 0.0 ? 1 : x < 0.0 ? -1 : 0)
354 
355 /**
356  * Evalaute the derivative of an edge endpoint
357  *
358  * @param h0 input interval of the interval closest to the edge
359  * @param h1 input interval of the interval next to the closest
360  * @param m0 linear slope of the interval closest to the edge
361  * @param m1 linear slope of the intervalnext to the closest
362  * @return edge endpoint derivative
363  *
364  * Based on scipy.interpolate._edge_case()
365  * https://github.com/scipy/scipy/blob/2e5883ef7af4f5ed4a5b80a1759a45e43163bf3f/scipy/interpolate/_cubic.py#L239
366  * which is a python implementation of the special case endpoints, as suggested in
367  * Cleve Moler, Numerical Computing with MATLAB, Chap 3.6 (pchiptx.m)
368 */
369 static double pchip_edge_case(double h0, double h1, double m0, double m1)
370 {
371  int mask, mask2;
372  double d;
373 
374  d = ((2 * h0 + h1) * m0 - h0 * m1) / (h0 + h1);
375 
376  mask = SIGN(d) != SIGN(m0);
377  mask2 = (SIGN(m0) != SIGN(m1)) && (fabs(d) > 3. * fabs(m0));
378 
379  if (mask) d = 0.0;
380  else if (mask2) d = 3.0 * m0;
381 
382  return d;
383 }
384 
385 /**
386  * Evalaute the piecewise polynomial derivatives at endpoints
387  *
388  * @param n input interval of the interval closest to the edge
389  * @param hk input intervals
390  * @param mk linear slopes over intervals
391  * @param dk endpoint derivatives (output)
392  * @return 0 success
393  *
394  * Based on scipy.interpolate._find_derivatives()
395  * https://github.com/scipy/scipy/blob/2e5883ef7af4f5ed4a5b80a1759a45e43163bf3f/scipy/interpolate/_cubic.py#L254
396 */
397 
398 static int pchip_find_derivatives(const int n, const double *hk, const double *mk, double *dk)
399 {
400  int ret = 0;
401  const int m = n - 1;
402  int8_t *smk;
403 
404  smk = av_malloc(n);
405  if (!smk) {
406  ret = AVERROR(ENOMEM);
407  goto end;
408  }
409 
410  /* smk = sgn(mk) */
411  for (int i = 0; i < n; i++) smk[i] = SIGN(mk[i]);
412 
413  /* check the strict monotonicity */
414  for (int i = 0; i < m; i++) {
415  int8_t condition = (smk[i + 1] != smk[i]) || (mk[i + 1] == 0) || (mk[i] == 0);
416  if (condition) {
417  dk[i + 1] = 0.0;
418  } else {
419  double w1 = 2 * hk[i + 1] + hk[i];
420  double w2 = hk[i + 1] + 2 * hk[i];
421  dk[i + 1] = (w1 + w2) / (w1 / mk[i] + w2 / mk[i + 1]);
422  }
423  }
424 
425  dk[0] = pchip_edge_case(hk[0], hk[1], mk[0], mk[1]);
426  dk[n] = pchip_edge_case(hk[n - 1], hk[n - 2], mk[n - 1], mk[n - 2]);
427 
428 end:
429  av_free(smk);
430 
431  return ret;
432 }
433 
434 /**
435  * Evalaute half of the cubic hermite interpolation expression, wrt one interval endpoint
436  *
437  * @param x normalized input value at the endpoint
438  * @param f output value at the endpoint
439  * @param d derivative at the endpoint: normalized to the interval, and properly sign adjusted
440  * @return half of the interpolated value
441 */
442 static inline double interp_cubic_hermite_half(const double x, const double f,
443  const double d)
444 {
445  double x2 = x * x, x3 = x2 * x;
446  return f * (3.0 * x2 - 2.0 * x3) + d * (x3 - x2);
447 }
448 
449 /**
450  * Prepare the lookup table by piecewise monotonic cubic interpolation (PCHIP)
451  *
452  * @param log_ctx for logging
453  * @param y output lookup table (output)
454  * @param points user-defined control points/endpoints
455  * @param nbits bitdepth
456  * @return 0 success
457  *
458  * References:
459  * [1] F. N. Fritsch and J. Butland, A method for constructing local monotone piecewise
460  * cubic interpolants, SIAM J. Sci. Comput., 5(2), 300-304 (1984). DOI:10.1137/0905021.
461  * [2] scipy.interpolate: https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.PchipInterpolator.html
462 */
463 static inline int interpolate_pchip(void *log_ctx, uint16_t *y,
464  const struct keypoint *points, int nbits)
465 {
466  const struct keypoint *point = points;
467  const int lut_size = 1<<nbits;
468  const int n = get_nb_points(points); // number of endpoints
469  double *xi, *fi, *di, *hi, *mi;
470  const int scale = lut_size - 1; // white value
471  uint16_t x; /* input index/value */
472  int ret = 0;
473 
474  /* no change for n = 0 or 1 */
475  if (n == 0) {
476  /* no points, no change */
477  for (int i = 0; i < lut_size; i++) y[i] = i;
478  return 0;
479  }
480 
481  if (n == 1) {
482  /* 1 point - 1 color everywhere */
483  const uint16_t yval = CLIP(point->y * scale);
484  for (int i = 0; i < lut_size; i++) y[i] = yval;
485  return 0;
486  }
487 
488  xi = av_calloc(3*n + 2*(n-1), sizeof(double)); /* output values at interval endpoints */
489  if (!xi) {
490  ret = AVERROR(ENOMEM);
491  goto end;
492  }
493 
494  fi = xi + n; /* output values at inteval endpoints */
495  di = fi + n; /* output slope wrt normalized input at interval endpoints */
496  hi = di + n; /* interval widths */
497  mi = hi + n - 1; /* linear slope over intervals */
498 
499  /* scale endpoints and store them in a contiguous memory block */
500  for (int i = 0; i < n; i++) {
501  xi[i] = point->x * scale;
502  fi[i] = point->y * scale;
503  point = point->next;
504  }
505 
506  /* h(i) = x(i+1) - x(i); mi(i) = (f(i+1)-f(i))/h(i) */
507  for (int i = 0; i < n - 1; i++) {
508  const double val = (xi[i+1]-xi[i]);
509  hi[i] = val;
510  mi[i] = (fi[i+1]-fi[i]) / val;
511  }
512 
513  if (n == 2) {
514  /* edge case, use linear interpolation */
515  const double m = mi[0], b = fi[0] - xi[0]*m;
516  for (int i = 0; i < lut_size; i++) y[i] = CLIP(i*m + b);
517  goto end;
518  }
519 
520  /* compute the derivatives at the endpoints*/
521  ret = pchip_find_derivatives(n-1, hi, mi, di);
522  if (ret)
523  goto end;
524 
525  /* interpolate/extrapolate */
526  x = 0;
527  if (xi[0] > 0) {
528  /* below first endpoint, use the first endpoint value*/
529  const double xi0 = xi[0];
530  const double yi0 = fi[0];
531  const uint16_t yval = CLIP(yi0);
532  for (; x < xi0; x++) {
533  y[x] = yval;
534  av_log(log_ctx, AV_LOG_TRACE, "f(%f)=%f -> y[%d]=%d\n", xi0, yi0, x, y[x]);
535  }
536  av_log(log_ctx, AV_LOG_DEBUG, "Interval -1: [0, %d] -> %d\n", x - 1, yval);
537  }
538 
539  /* for each interval */
540  for (int i = 0, x0 = x; i < n-1; i++, x0 = x) {
541  const double xi0 = xi[i]; /* start-of-interval input value */
542  const double xi1 = xi[i + 1]; /* end-of-interval input value */
543  const double h = hi[i]; /* interval width */
544  const double f0 = fi[i]; /* start-of-interval output value */
545  const double f1 = fi[i + 1]; /* end-of-interval output value */
546  const double d0 = di[i]; /* start-of-interval derivative */
547  const double d1 = di[i + 1]; /* end-of-interval derivative */
548 
549  /* fill the lut over the interval */
550  for (; x < xi1; x++) { /* safe not to check j < lut_size */
551  const double xx = (x - xi0) / h; /* normalize input */
552  const double yy = interp_cubic_hermite_half(1 - xx, f0, -h * d0)
553  + interp_cubic_hermite_half(xx, f1, h * d1);
554  y[x] = CLIP(yy);
555  av_log(log_ctx, AV_LOG_TRACE, "f(%f)=%f -> y[%d]=%d\n", xx, yy, x, y[x]);
556  }
557 
558  if (x > x0)
559  av_log(log_ctx, AV_LOG_DEBUG, "Interval %d: [%d, %d] -> [%d, %d]\n",
560  i, x0, x-1, y[x0], y[x-1]);
561  else
562  av_log(log_ctx, AV_LOG_DEBUG, "Interval %d: empty\n", i);
563  }
564 
565  if (x && x < lut_size) {
566  /* above the last endpoint, use the last endpoint value*/
567  const double xi1 = xi[n - 1];
568  const double yi1 = fi[n - 1];
569  const uint16_t yval = CLIP(yi1);
570  av_log(log_ctx, AV_LOG_DEBUG, "Interval %d: [%d, %d] -> %d\n",
571  n-1, x, lut_size - 1, yval);
572  for (; x && x < lut_size; x++) { /* loop until int overflow */
573  y[x] = yval;
574  av_log(log_ctx, AV_LOG_TRACE, "f(%f)=%f -> y[%d]=%d\n", xi1, yi1, x, yval);
575  }
576  }
577 
578 end:
579  av_free(xi);
580  return ret;
581 }
582 
583 
584 static int parse_psfile(AVFilterContext *ctx, const char *fname)
585 {
586  CurvesContext *curves = ctx->priv;
587  uint8_t *buf;
588  size_t size;
589  int i, ret, av_unused(version), nb_curves;
590  AVBPrint ptstr;
591  static const int comp_ids[] = {3, 0, 1, 2};
592 
594 
595  ret = av_file_map(fname, &buf, &size, 0, NULL);
596  if (ret < 0)
597  return ret;
598 
599 #define READ16(dst) do { \
600  if (size < 2) { \
601  ret = AVERROR_INVALIDDATA; \
602  goto end; \
603  } \
604  dst = AV_RB16(buf); \
605  buf += 2; \
606  size -= 2; \
607 } while (0)
608 
609  READ16(version);
610  READ16(nb_curves);
611  for (i = 0; i < FFMIN(nb_curves, FF_ARRAY_ELEMS(comp_ids)); i++) {
612  int nb_points, n;
613  av_bprint_clear(&ptstr);
614  READ16(nb_points);
615  for (n = 0; n < nb_points; n++) {
616  int y, x;
617  READ16(y);
618  READ16(x);
619  av_bprintf(&ptstr, "%f/%f ", x / 255., y / 255.);
620  }
621  if (*ptstr.str) {
622  char **pts = &curves->comp_points_str[comp_ids[i]];
623  if (!*pts) {
624  *pts = av_strdup(ptstr.str);
625  av_log(ctx, AV_LOG_DEBUG, "curves %d (intid=%d) [%d points]: [%s]\n",
626  i, comp_ids[i], nb_points, *pts);
627  if (!*pts) {
628  ret = AVERROR(ENOMEM);
629  goto end;
630  }
631  }
632  }
633  }
634 end:
635  av_bprint_finalize(&ptstr, NULL);
636  av_file_unmap(buf, size);
637  return ret;
638 }
639 
640 static int dump_curves(const char *fname, uint16_t *graph[NB_COMP + 1],
641  struct keypoint *comp_points[NB_COMP + 1],
642  int lut_size)
643 {
644  int i;
645  AVBPrint buf;
646  const double scale = 1. / (lut_size - 1);
647  static const char * const colors[] = { "red", "green", "blue", "#404040", };
648  FILE *f = avpriv_fopen_utf8(fname, "w");
649 
650  av_assert0(FF_ARRAY_ELEMS(colors) == NB_COMP + 1);
651 
652  if (!f) {
653  int ret = AVERROR(errno);
654  av_log(NULL, AV_LOG_ERROR, "Cannot open file '%s' for writing: %s\n",
655  fname, av_err2str(ret));
656  return ret;
657  }
658 
660 
661  av_bprintf(&buf, "set xtics 0.1\n");
662  av_bprintf(&buf, "set ytics 0.1\n");
663  av_bprintf(&buf, "set size square\n");
664  av_bprintf(&buf, "set grid\n");
665 
666  for (i = 0; i < FF_ARRAY_ELEMS(colors); i++) {
667  av_bprintf(&buf, "%s'-' using 1:2 with lines lc '%s' title ''",
668  i ? ", " : "plot ", colors[i]);
669  if (comp_points[i])
670  av_bprintf(&buf, ", '-' using 1:2 with points pointtype 3 lc '%s' title ''",
671  colors[i]);
672  }
673  av_bprintf(&buf, "\n");
674 
675  for (i = 0; i < FF_ARRAY_ELEMS(colors); i++) {
676  int x;
677 
678  /* plot generated values */
679  for (x = 0; x < lut_size; x++)
680  av_bprintf(&buf, "%f %f\n", x * scale, graph[i][x] * scale);
681  av_bprintf(&buf, "e\n");
682 
683  /* plot user knots */
684  if (comp_points[i]) {
685  const struct keypoint *point = comp_points[i];
686 
687  while (point) {
688  av_bprintf(&buf, "%f %f\n", point->x, point->y);
689  point = point->next;
690  }
691  av_bprintf(&buf, "e\n");
692  }
693  }
694 
695  fwrite(buf.str, 1, buf.len, f);
696  fclose(f);
697  av_bprint_finalize(&buf, NULL);
698  return 0;
699 }
700 
702 {
703  int i, ret;
704  CurvesContext *curves = ctx->priv;
705  char **pts = curves->comp_points_str;
706  const char *allp = curves->comp_points_str_all;
707 
708  //if (!allp && curves->preset != PRESET_NONE && curves_presets[curves->preset].all)
709  // allp = curves_presets[curves->preset].all;
710 
711  if (allp) {
712  for (i = 0; i < NB_COMP; i++) {
713  if (!pts[i])
714  pts[i] = av_strdup(allp);
715  if (!pts[i])
716  return AVERROR(ENOMEM);
717  }
718  }
719 
720  if (curves->psfile && !curves->parsed_psfile) {
721  ret = parse_psfile(ctx, curves->psfile);
722  if (ret < 0)
723  return ret;
724  curves->parsed_psfile = 1;
725  }
726 
727  if (curves->preset != PRESET_NONE) {
728 #define SET_COMP_IF_NOT_SET(n, name) do { \
729  if (!pts[n] && curves_presets[curves->preset].name) { \
730  pts[n] = av_strdup(curves_presets[curves->preset].name); \
731  if (!pts[n]) \
732  return AVERROR(ENOMEM); \
733  } \
734 } while (0)
739  curves->preset = PRESET_NONE;
740  }
741 
742  return 0;
743 }
744 
745 static int filter_slice_packed(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
746 {
747  int x, y;
748  const CurvesContext *curves = ctx->priv;
749  const ThreadData *td = arg;
750  const AVFrame *in = td->in;
751  const AVFrame *out = td->out;
752  const int direct = out == in;
753  const int step = curves->step;
754  const uint8_t r = curves->rgba_map[R];
755  const uint8_t g = curves->rgba_map[G];
756  const uint8_t b = curves->rgba_map[B];
757  const uint8_t a = curves->rgba_map[A];
758  const int slice_start = (in->height * jobnr ) / nb_jobs;
759  const int slice_end = (in->height * (jobnr+1)) / nb_jobs;
760 
761  if (curves->is_16bit) {
762  for (y = slice_start; y < slice_end; y++) {
763  uint16_t *dstp = ( uint16_t *)(out->data[0] + y * out->linesize[0]);
764  const uint16_t *srcp = (const uint16_t *)(in ->data[0] + y * in->linesize[0]);
765 
766  for (x = 0; x < in->width * step; x += step) {
767  dstp[x + r] = curves->graph[R][srcp[x + r]];
768  dstp[x + g] = curves->graph[G][srcp[x + g]];
769  dstp[x + b] = curves->graph[B][srcp[x + b]];
770  if (!direct && step == 4)
771  dstp[x + a] = srcp[x + a];
772  }
773  }
774  } else {
775  uint8_t *dst = out->data[0] + slice_start * out->linesize[0];
776  const uint8_t *src = in->data[0] + slice_start * in->linesize[0];
777 
778  for (y = slice_start; y < slice_end; y++) {
779  for (x = 0; x < in->width * step; x += step) {
780  dst[x + r] = curves->graph[R][src[x + r]];
781  dst[x + g] = curves->graph[G][src[x + g]];
782  dst[x + b] = curves->graph[B][src[x + b]];
783  if (!direct && step == 4)
784  dst[x + a] = src[x + a];
785  }
786  dst += out->linesize[0];
787  src += in ->linesize[0];
788  }
789  }
790  return 0;
791 }
792 
793 static int filter_slice_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
794 {
795  int x, y;
796  const CurvesContext *curves = ctx->priv;
797  const ThreadData *td = arg;
798  const AVFrame *in = td->in;
799  const AVFrame *out = td->out;
800  const int direct = out == in;
801  const int step = curves->step;
802  const uint8_t r = curves->rgba_map[R];
803  const uint8_t g = curves->rgba_map[G];
804  const uint8_t b = curves->rgba_map[B];
805  const uint8_t a = curves->rgba_map[A];
806  const int slice_start = (in->height * jobnr ) / nb_jobs;
807  const int slice_end = (in->height * (jobnr+1)) / nb_jobs;
808 
809  if (curves->is_16bit) {
810  for (y = slice_start; y < slice_end; y++) {
811  uint16_t *dstrp = ( uint16_t *)(out->data[r] + y * out->linesize[r]);
812  uint16_t *dstgp = ( uint16_t *)(out->data[g] + y * out->linesize[g]);
813  uint16_t *dstbp = ( uint16_t *)(out->data[b] + y * out->linesize[b]);
814  uint16_t *dstap = ( uint16_t *)(out->data[a] + y * out->linesize[a]);
815  const uint16_t *srcrp = (const uint16_t *)(in ->data[r] + y * in->linesize[r]);
816  const uint16_t *srcgp = (const uint16_t *)(in ->data[g] + y * in->linesize[g]);
817  const uint16_t *srcbp = (const uint16_t *)(in ->data[b] + y * in->linesize[b]);
818  const uint16_t *srcap = (const uint16_t *)(in ->data[a] + y * in->linesize[a]);
819 
820  for (x = 0; x < in->width; x++) {
821  dstrp[x] = curves->graph[R][srcrp[x]];
822  dstgp[x] = curves->graph[G][srcgp[x]];
823  dstbp[x] = curves->graph[B][srcbp[x]];
824  if (!direct && step == 4)
825  dstap[x] = srcap[x];
826  }
827  }
828  } else {
829  uint8_t *dstr = out->data[r] + slice_start * out->linesize[r];
830  uint8_t *dstg = out->data[g] + slice_start * out->linesize[g];
831  uint8_t *dstb = out->data[b] + slice_start * out->linesize[b];
832  uint8_t *dsta = out->data[a] + slice_start * out->linesize[a];
833  const uint8_t *srcr = in->data[r] + slice_start * in->linesize[r];
834  const uint8_t *srcg = in->data[g] + slice_start * in->linesize[g];
835  const uint8_t *srcb = in->data[b] + slice_start * in->linesize[b];
836  const uint8_t *srca = in->data[a] + slice_start * in->linesize[a];
837 
838  for (y = slice_start; y < slice_end; y++) {
839  for (x = 0; x < in->width; x++) {
840  dstr[x] = curves->graph[R][srcr[x]];
841  dstg[x] = curves->graph[G][srcg[x]];
842  dstb[x] = curves->graph[B][srcb[x]];
843  if (!direct && step == 4)
844  dsta[x] = srca[x];
845  }
846  dstr += out->linesize[r];
847  dstg += out->linesize[g];
848  dstb += out->linesize[b];
849  dsta += out->linesize[a];
850  srcr += in ->linesize[r];
851  srcg += in ->linesize[g];
852  srcb += in ->linesize[b];
853  srca += in ->linesize[a];
854  }
855  }
856  return 0;
857 }
858 
860 {
861  int i, j, ret;
862  AVFilterContext *ctx = inlink->dst;
863  CurvesContext *curves = ctx->priv;
865  char **pts = curves->comp_points_str;
866  struct keypoint *comp_points[NB_COMP + 1] = {0};
867 
868  ff_fill_rgba_map(curves->rgba_map, inlink->format);
869  curves->is_16bit = desc->comp[0].depth > 8;
870  curves->depth = desc->comp[0].depth;
871  curves->lut_size = 1 << curves->depth;
872  curves->step = av_get_padded_bits_per_pixel(desc) >> (3 + curves->is_16bit);
874 
875  for (i = 0; i < NB_COMP + 1; i++) {
876  if (!curves->graph[i])
877  curves->graph[i] = av_calloc(curves->lut_size, sizeof(*curves->graph[0]));
878  if (!curves->graph[i])
879  return AVERROR(ENOMEM);
880  ret = parse_points_str(ctx, comp_points + i, curves->comp_points_str[i], curves->lut_size);
881  if (ret < 0)
882  return ret;
883  if (curves->interp == INTERP_PCHIP)
884  ret = interpolate_pchip(ctx, curves->graph[i], comp_points[i], curves->depth);
885  else
886  ret = interpolate(ctx, curves->graph[i], comp_points[i], curves->depth);
887  if (ret < 0)
888  return ret;
889  }
890 
891  if (pts[NB_COMP]) {
892  for (i = 0; i < NB_COMP; i++)
893  for (j = 0; j < curves->lut_size; j++)
894  curves->graph[i][j] = curves->graph[NB_COMP][curves->graph[i][j]];
895  }
896 
897  if (av_log_get_level() >= AV_LOG_VERBOSE) {
898  for (i = 0; i < NB_COMP; i++) {
899  const struct keypoint *point = comp_points[i];
900  av_log(ctx, AV_LOG_VERBOSE, "#%d points:", i);
901  while (point) {
902  av_log(ctx, AV_LOG_VERBOSE, " (%f;%f)", point->x, point->y);
903  point = point->next;
904  }
905  }
906  }
907 
908  if (curves->plot_filename && !curves->saved_plot) {
909  dump_curves(curves->plot_filename, curves->graph, comp_points, curves->lut_size);
910  curves->saved_plot = 1;
911  }
912 
913  for (i = 0; i < NB_COMP + 1; i++) {
914  struct keypoint *point = comp_points[i];
915  while (point) {
916  struct keypoint *next = point->next;
917  av_free(point);
918  point = next;
919  }
920  }
921 
922  return 0;
923 }
924 
926 {
927  AVFilterContext *ctx = inlink->dst;
928  CurvesContext *curves = ctx->priv;
929  AVFilterLink *outlink = ctx->outputs[0];
930  AVFrame *out;
931  ThreadData td;
932 
933  if (av_frame_is_writable(in)) {
934  out = in;
935  } else {
936  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
937  if (!out) {
938  av_frame_free(&in);
939  return AVERROR(ENOMEM);
940  }
942  }
943 
944  td.in = in;
945  td.out = out;
946  ff_filter_execute(ctx, curves->filter_slice, &td, NULL,
947  FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
948 
949  if (out != in)
950  av_frame_free(&in);
951 
952  return ff_filter_frame(outlink, out);
953 }
954 
955 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
956  char *res, int res_len, int flags)
957 {
958  CurvesContext *curves = ctx->priv;
959  int ret;
960 
961  if (!strcmp(cmd, "plot")) {
962  curves->saved_plot = 0;
963  } else if (!strcmp(cmd, "all") || !strcmp(cmd, "preset") || !strcmp(cmd, "psfile") || !strcmp(cmd, "interp")) {
964  if (!strcmp(cmd, "psfile"))
965  curves->parsed_psfile = 0;
966  av_freep(&curves->comp_points_str_all);
967  av_freep(&curves->comp_points_str[0]);
968  av_freep(&curves->comp_points_str[1]);
969  av_freep(&curves->comp_points_str[2]);
970  av_freep(&curves->comp_points_str[NB_COMP]);
971  } else if (!strcmp(cmd, "red") || !strcmp(cmd, "r")) {
972  av_freep(&curves->comp_points_str[0]);
973  } else if (!strcmp(cmd, "green") || !strcmp(cmd, "g")) {
974  av_freep(&curves->comp_points_str[1]);
975  } else if (!strcmp(cmd, "blue") || !strcmp(cmd, "b")) {
976  av_freep(&curves->comp_points_str[2]);
977  } else if (!strcmp(cmd, "master") || !strcmp(cmd, "m")) {
978  av_freep(&curves->comp_points_str[NB_COMP]);
979  }
980 
981  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
982  if (ret < 0)
983  return ret;
984 
985  ret = curves_init(ctx);
986  if (ret < 0)
987  return ret;
988  return config_input(ctx->inputs[0]);
989 }
990 
992 {
993  int i;
994  CurvesContext *curves = ctx->priv;
995 
996  for (i = 0; i < NB_COMP + 1; i++)
997  av_freep(&curves->graph[i]);
998 }
999 
1000 static const AVFilterPad curves_inputs[] = {
1001  {
1002  .name = "default",
1003  .type = AVMEDIA_TYPE_VIDEO,
1004  .filter_frame = filter_frame,
1005  .config_props = config_input,
1006  },
1007 };
1008 
1010  .name = "curves",
1011  .description = NULL_IF_CONFIG_SMALL("Adjust components curves."),
1012  .priv_size = sizeof(CurvesContext),
1013  .init = curves_init,
1014  .uninit = curves_uninit,
1030  .priv_class = &curves_class,
1032  .process_command = process_command,
1033 };
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:112
AV_PIX_FMT_GBRAP16
#define AV_PIX_FMT_GBRAP16
Definition: pixfmt.h:501
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:73
td
#define td
Definition: regdef.h:70
PRESET_CROSS_PROCESS
@ PRESET_CROSS_PROCESS
Definition: vf_curves.c:50
READ16
#define READ16(dst)
PRESET_LIGHTER
@ PRESET_LIGHTER
Definition: vf_curves.c:53
r
const char * r
Definition: vf_curves.c:127
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:75
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:640
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:442
out
FILE * out
Definition: movenc.c:55
curves
static const Curve curves[]
Definition: vf_pseudocolor.c:192
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:42
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1015
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2965
matrix
Definition: vc1dsp.c:43
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:93
CurvesContext::saved_plot
int saved_plot
Definition: vf_curves.c:79
PRESET_MEDIUM_CONTRAST
@ PRESET_MEDIUM_CONTRAST
Definition: vf_curves.c:55
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:160
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:374
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:446
AVOption
AVOption.
Definition: opt.h:346
data
const char data[16]
Definition: mxf.c:148
CurvesContext
Definition: vf_curves.c:68
curves_inputs
static const AVFilterPad curves_inputs[]
Definition: vf_curves.c:1000
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:76
AV_PIX_FMT_BGRA
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:102
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:170
BD
#define BD
ThreadData::out
AVFrame * out
Definition: af_adeclick.c:527
get_nb_points
static int get_nb_points(const struct keypoint *d)
Definition: vf_curves.c:212
CurvesContext::rgba_map
uint8_t rgba_map[4]
Definition: vf_curves.c:76
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:395
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:85
A
#define A
Definition: vf_curves.c:38
AV_PIX_FMT_GBRP14
#define AV_PIX_FMT_GBRP14
Definition: pixfmt.h:496
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:55
AV_PIX_FMT_GBRAP
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
Definition: pixfmt.h:212
interp
interp
Definition: vf_curves.c:62
AV_PIX_FMT_GBRP10
#define AV_PIX_FMT_GBRP10
Definition: pixfmt.h:494
NB_PRESETS
@ NB_PRESETS
Definition: vf_curves.c:59
CurvesContext::preset
int preset
Definition: vf_curves.c:70
AV_BPRINT_SIZE_AUTOMATIC
#define AV_BPRINT_SIZE_AUTOMATIC
val
static double val(void *priv, double ch)
Definition: aeval.c:78
pts
static int64_t pts
Definition: transcode_aac.c:644
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:33
preset
preset
Definition: vf_curves.c:47
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
ff_video_default_filterpad
const AVFilterPad ff_video_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_VIDEO.
Definition: video.c:37
mask
static const uint16_t mask[17]
Definition: lzw.c:38
AV_PIX_FMT_GBRAP10
#define AV_PIX_FMT_GBRAP10
Definition: pixfmt.h:498
keypoint::x
double x
Definition: vf_curves.c:41
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:198
AV_PIX_FMT_GBRAP12
#define AV_PIX_FMT_GBRAP12
Definition: pixfmt.h:499
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:955
mi
#define mi
Definition: vf_colormatrix.c:106
g
const char * g
Definition: vf_curves.c:128
keypoint
Definition: vf_curves.c:40
slice_end
static int slice_end(AVCodecContext *avctx, AVFrame *pict)
Handle slice ends.
Definition: mpeg12dec.c:1730
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:40
CLIP
#define CLIP(v)
Natural cubic spline interpolation Finding curves using Cubic Splines notes by Steven Rauch and John ...
Definition: vf_curves.c:228
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:49
xi
#define xi(width, name, var, range_min, range_max, subs,...)
Definition: cbs_h2645.c:418
CurvesContext::lut_size
int lut_size
Definition: vf_curves.c:74
CurvesContext::is_16bit
int is_16bit
Definition: vf_curves.c:80
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: internal.h:182
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:146
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:100
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:442
AV_PIX_FMT_GBRP16
#define AV_PIX_FMT_GBRP16
Definition: pixfmt.h:497
curves_presets
static const struct @278 curves_presets[]
AV_PIX_FMT_RGBA64
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:468
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:230
fabs
static __device__ float fabs(float a)
Definition: cuda_runtime.h:182
AV_PIX_FMT_BGR48
#define AV_PIX_FMT_BGR48
Definition: pixfmt.h:469
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:709
G
#define G
Definition: vf_curves.c:36
INTERP_PCHIP
@ INTERP_PCHIP
Definition: vf_curves.c:64
CurvesContext::parsed_psfile
int parsed_psfile
Definition: vf_curves.c:82
double
double
Definition: af_crystalizer.c:131
AV_PIX_FMT_BGR0
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:265
CurvesContext::depth
int depth
Definition: vf_curves.c:81
AV_PIX_FMT_GBRP9
#define AV_PIX_FMT_GBRP9
Definition: pixfmt.h:493
AV_PIX_FMT_ABGR
@ AV_PIX_FMT_ABGR
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
Definition: pixfmt.h:101
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:129
CurvesContext::interp
int interp
Definition: vf_curves.c:83
PRESET_DARKER
@ PRESET_DARKER
Definition: vf_curves.c:51
eval.h
AD
#define AD
f
f
Definition: af_crystalizer.c:121
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:366
AV_PIX_FMT_RGB24
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:75
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:94
master
const char * master
Definition: vf_curves.c:130
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:240
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:2930
FILTER_PIXFMTS
#define FILTER_PIXFMTS(...)
Definition: internal.h:168
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:1009
AV_PIX_FMT_RGB48
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:464
size
int size
Definition: twinvq_data.h:10344
curves_uninit
static av_cold void curves_uninit(AVFilterContext *ctx)
Definition: vf_curves.c:991
av_frame_is_writable
int av_frame_is_writable(AVFrame *frame)
Check if the frame data is writable.
Definition: frame.c:645
filter_slice_planar
static int filter_slice_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_curves.c:793
INTERP_NATURAL
@ INTERP_NATURAL
Definition: vf_curves.c:63
NB_INTERPS
@ NB_INTERPS
Definition: vf_curves.c:65
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:887
curves_options
static const AVOption curves_options[]
Definition: vf_curves.c:94
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:263
version
version
Definition: libkvazaar.c:321
filter_slice_packed
static int filter_slice_packed(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_curves.c:745
CurvesContext::plot_filename
char * plot_filename
Definition: vf_curves.c:78
SIGN
#define SIGN(x)
Definition: vf_curves.c:353
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:147
AV_PIX_FMT_ARGB
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition: pixfmt.h:99
CurvesContext::comp_points_str
char * comp_points_str[NB_COMP+1]
Definition: vf_curves.c:71
PRESET_INCREASE_CONTRAST
@ PRESET_INCREASE_CONTRAST
Definition: vf_curves.c:52
uninit
static void uninit(AVBSFContext *ctx)
Definition: pcm_rechunk.c:68
AV_PIX_FMT_BGRA64
#define AV_PIX_FMT_BGRA64
Definition: pixfmt.h:473
bprint.h
PRESET_NONE
@ PRESET_NONE
Definition: vf_curves.c:48
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
B
#define B
Definition: vf_curves.c:37
CurvesContext::step
int step
Definition: vf_curves.c:77
AV_PIX_FMT_GBRP12
#define AV_PIX_FMT_GBRP12
Definition: pixfmt.h:495
ff_filter_get_nb_threads
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:827
ThreadData
Used for passing data between threads.
Definition: dsddec.c:71
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:256
PRESET_VINTAGE
@ PRESET_VINTAGE
Definition: vf_curves.c:58
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:39
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:49
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
AVFilter
Filter definition.
Definition: avfilter.h:166
NB_COMP
#define NB_COMP
Definition: vf_curves.c:45
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:264
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:107
R
#define R
Definition: vf_curves.c:35
CurvesContext::comp_points_str_all
char * comp_points_str_all
Definition: vf_curves.c:72
PRESET_NEGATIVE
@ PRESET_NEGATIVE
Definition: vf_curves.c:56
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:99
AVFrame::height
int height
Definition: frame.h:446
PRESET_LINEAR_CONTRAST
@ PRESET_LINEAR_CONTRAST
Definition: vf_curves.c:54
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:235
avfilter.h
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:232
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:398
make_point
static struct keypoint * make_point(double x, double y, struct keypoint *next)
Definition: vf_curves.c:156
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
slice_start
static int slice_start(SliceContext *sc, VVCContext *s, VVCFrameContext *fc, const CodedBitstreamUnit *unit, const int is_first_slice)
Definition: dec.c:688
config_input
static int config_input(AVFilterLink *inlink)
Definition: vf_curves.c:859
file.h
AVFilterContext
An instance of a filter.
Definition: avfilter.h:407
AV_PIX_FMT_GBRP
@ AV_PIX_FMT_GBRP
planar GBR 4:4:4 24bpp
Definition: pixfmt.h:165
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:272
desc
const char * desc
Definition: libsvtav1.c:75
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
mem.h
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:701
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
scale
static void scale(int *out, const int *in, const int w, const int h, const int shift)
Definition: intra.c:291
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:183
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:463
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:41
parse_psfile
static int parse_psfile(AVFilterContext *ctx, const char *fname)
Definition: vf_curves.c:584
parse_points_str
static int parse_points_str(AVFilterContext *ctx, struct keypoint **points, const char *s, int lut_size)
Definition: vf_curves.c:168
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:424
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:369
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:474
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:419
AV_PIX_FMT_0RGB
@ AV_PIX_FMT_0RGB
packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined
Definition: pixfmt.h:262
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
h
h
Definition: vp9dsp_template.c:2038
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:239
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:134
PRESET_STRONG_CONTRAST
@ PRESET_STRONG_CONTRAST
Definition: vf_curves.c:57
int
int
Definition: ffmpeg_filter.c:424
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:244
OFFSET
#define OFFSET(x)
Definition: vf_curves.c:92
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_curves.c:925