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  av_free(point);
186  return AVERROR(EINVAL);
187  }
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  av_free(point);
195  return AVERROR(EINVAL);
196  }
197  last->next = point;
198  }
199  if (!*points)
200  *points = point;
201  last = point;
202  }
203 
204  if (*points && !(*points)->next) {
205  av_log(ctx, AV_LOG_WARNING, "Only one point (at (%f;%f)) is defined, "
206  "this is unlikely to behave as you expect. You probably want"
207  "at least 2 points.",
208  (*points)->x, (*points)->y);
209  }
210 
211  return 0;
212 }
213 
214 static int get_nb_points(const struct keypoint *d)
215 {
216  int n = 0;
217  while (d) {
218  n++;
219  d = d->next;
220  }
221  return n;
222 }
223 
224 /**
225  * Natural cubic spline interpolation
226  * Finding curves using Cubic Splines notes by Steven Rauch and John Stockie.
227  * @see http://people.math.sfu.ca/~stockie/teaching/macm316/notes/splines.pdf
228  */
229 
230 #define CLIP(v) (nbits == 8 ? av_clip_uint8(v) : av_clip_uintp2_c(v, nbits))
231 
232 static inline int interpolate(void *log_ctx, uint16_t *y,
233  const struct keypoint *points, int nbits)
234 {
235  int i, ret = 0;
236  const struct keypoint *point = points;
237  double xprev = 0;
238  const int lut_size = 1<<nbits;
239  const int scale = lut_size - 1;
240 
241  double (*matrix)[3];
242  double *h, *r;
243  const int n = get_nb_points(points); // number of splines
244 
245  if (n == 0) {
246  for (i = 0; i < lut_size; i++)
247  y[i] = i;
248  return 0;
249  }
250 
251  if (n == 1) {
252  for (i = 0; i < lut_size; i++)
253  y[i] = CLIP(point->y * scale);
254  return 0;
255  }
256 
257  matrix = av_calloc(n, sizeof(*matrix));
258  h = av_malloc((n - 1) * sizeof(*h));
259  r = av_calloc(n, sizeof(*r));
260 
261  if (!matrix || !h || !r) {
262  ret = AVERROR(ENOMEM);
263  goto end;
264  }
265 
266  /* h(i) = x(i+1) - x(i) */
267  i = -1;
268  for (point = points; point; point = point->next) {
269  if (i != -1)
270  h[i] = point->x - xprev;
271  xprev = point->x;
272  i++;
273  }
274 
275  /* right-side of the polynomials, will be modified to contains the solution */
276  point = points;
277  for (i = 1; i < n - 1; i++) {
278  const double yp = point->y;
279  const double yc = point->next->y;
280  const double yn = point->next->next->y;
281  r[i] = 6 * ((yn-yc)/h[i] - (yc-yp)/h[i-1]);
282  point = point->next;
283  }
284 
285 #define BD 0 /* sub diagonal (below main) */
286 #define MD 1 /* main diagonal (center) */
287 #define AD 2 /* sup diagonal (above main) */
288 
289  /* left side of the polynomials into a tridiagonal matrix. */
290  matrix[0][MD] = matrix[n - 1][MD] = 1;
291  for (i = 1; i < n - 1; i++) {
292  matrix[i][BD] = h[i-1];
293  matrix[i][MD] = 2 * (h[i-1] + h[i]);
294  matrix[i][AD] = h[i];
295  }
296 
297  /* tridiagonal solving of the linear system */
298  for (i = 1; i < n; i++) {
299  const double den = matrix[i][MD] - matrix[i][BD] * matrix[i-1][AD];
300  const double k = den ? 1./den : 1.;
301  matrix[i][AD] *= k;
302  r[i] = (r[i] - matrix[i][BD] * r[i - 1]) * k;
303  }
304  for (i = n - 2; i >= 0; i--)
305  r[i] = r[i] - matrix[i][AD] * r[i + 1];
306 
307  point = points;
308 
309  /* left padding */
310  for (i = 0; i < (int)(point->x * scale); i++)
311  y[i] = CLIP(point->y * scale);
312 
313  /* compute the graph with x=[x0..xN] */
314  i = 0;
315  av_assert0(point->next); // always at least 2 key points
316  while (point->next) {
317  const double yc = point->y;
318  const double yn = point->next->y;
319 
320  const double a = yc;
321  const double b = (yn-yc)/h[i] - h[i]*r[i]/2. - h[i]*(r[i+1]-r[i])/6.;
322  const double c = r[i] / 2.;
323  const double d = (r[i+1] - r[i]) / (6.*h[i]);
324 
325  int x;
326  const int x_start = point->x * scale;
327  const int x_end = point->next->x * scale;
328 
329  av_assert0(x_start >= 0 && x_start < lut_size &&
330  x_end >= 0 && x_end < lut_size);
331 
332  for (x = x_start; x <= x_end; x++) {
333  const double xx = (x - x_start) * 1./scale;
334  const double yy = a + b*xx + c*xx*xx + d*xx*xx*xx;
335  y[x] = CLIP(yy * scale);
336  av_log(log_ctx, AV_LOG_DEBUG, "f(%f)=%f -> y[%d]=%d\n", xx, yy, x, y[x]);
337  }
338 
339  point = point->next;
340  i++;
341  }
342 
343  /* right padding */
344  for (i = (int)(point->x * scale); i < lut_size; i++)
345  y[i] = CLIP(point->y * scale);
346 
347 end:
348  av_free(matrix);
349  av_free(h);
350  av_free(r);
351  return ret;
352 
353 }
354 
355 #define SIGN(x) (x > 0.0 ? 1 : x < 0.0 ? -1 : 0)
356 
357 /**
358  * Evalaute the derivative of an edge endpoint
359  *
360  * @param h0 input interval of the interval closest to the edge
361  * @param h1 input interval of the interval next to the closest
362  * @param m0 linear slope of the interval closest to the edge
363  * @param m1 linear slope of the intervalnext to the closest
364  * @return edge endpoint derivative
365  *
366  * Based on scipy.interpolate._edge_case()
367  * https://github.com/scipy/scipy/blob/2e5883ef7af4f5ed4a5b80a1759a45e43163bf3f/scipy/interpolate/_cubic.py#L239
368  * which is a python implementation of the special case endpoints, as suggested in
369  * Cleve Moler, Numerical Computing with MATLAB, Chap 3.6 (pchiptx.m)
370 */
371 static double pchip_edge_case(double h0, double h1, double m0, double m1)
372 {
373  int mask, mask2;
374  double d;
375 
376  d = ((2 * h0 + h1) * m0 - h0 * m1) / (h0 + h1);
377 
378  mask = SIGN(d) != SIGN(m0);
379  mask2 = (SIGN(m0) != SIGN(m1)) && (fabs(d) > 3. * fabs(m0));
380 
381  if (mask) d = 0.0;
382  else if (mask2) d = 3.0 * m0;
383 
384  return d;
385 }
386 
387 /**
388  * Evalaute the piecewise polynomial derivatives at endpoints
389  *
390  * @param n input interval of the interval closest to the edge
391  * @param hk input intervals
392  * @param mk linear slopes over intervals
393  * @param dk endpoint derivatives (output)
394  * @return 0 success
395  *
396  * Based on scipy.interpolate._find_derivatives()
397  * https://github.com/scipy/scipy/blob/2e5883ef7af4f5ed4a5b80a1759a45e43163bf3f/scipy/interpolate/_cubic.py#L254
398 */
399 
400 static int pchip_find_derivatives(const int n, const double *hk, const double *mk, double *dk)
401 {
402  int ret = 0;
403  const int m = n - 1;
404  int8_t *smk;
405 
406  smk = av_malloc(n);
407  if (!smk) {
408  ret = AVERROR(ENOMEM);
409  goto end;
410  }
411 
412  /* smk = sgn(mk) */
413  for (int i = 0; i < n; i++) smk[i] = SIGN(mk[i]);
414 
415  /* check the strict monotonicity */
416  for (int i = 0; i < m; i++) {
417  int8_t condition = (smk[i + 1] != smk[i]) || (mk[i + 1] == 0) || (mk[i] == 0);
418  if (condition) {
419  dk[i + 1] = 0.0;
420  } else {
421  double w1 = 2 * hk[i + 1] + hk[i];
422  double w2 = hk[i + 1] + 2 * hk[i];
423  dk[i + 1] = (w1 + w2) / (w1 / mk[i] + w2 / mk[i + 1]);
424  }
425  }
426 
427  dk[0] = pchip_edge_case(hk[0], hk[1], mk[0], mk[1]);
428  dk[n] = pchip_edge_case(hk[n - 1], hk[n - 2], mk[n - 1], mk[n - 2]);
429 
430 end:
431  av_free(smk);
432 
433  return ret;
434 }
435 
436 /**
437  * Evalaute half of the cubic hermite interpolation expression, wrt one interval endpoint
438  *
439  * @param x normalized input value at the endpoint
440  * @param f output value at the endpoint
441  * @param d derivative at the endpoint: normalized to the interval, and properly sign adjusted
442  * @return half of the interpolated value
443 */
444 static inline double interp_cubic_hermite_half(const double x, const double f,
445  const double d)
446 {
447  double x2 = x * x, x3 = x2 * x;
448  return f * (3.0 * x2 - 2.0 * x3) + d * (x3 - x2);
449 }
450 
451 /**
452  * Prepare the lookup table by piecewise monotonic cubic interpolation (PCHIP)
453  *
454  * @param log_ctx for logging
455  * @param y output lookup table (output)
456  * @param points user-defined control points/endpoints
457  * @param nbits bitdepth
458  * @return 0 success
459  *
460  * References:
461  * [1] F. N. Fritsch and J. Butland, A method for constructing local monotone piecewise
462  * cubic interpolants, SIAM J. Sci. Comput., 5(2), 300-304 (1984). DOI:10.1137/0905021.
463  * [2] scipy.interpolate: https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.PchipInterpolator.html
464 */
465 static inline int interpolate_pchip(void *log_ctx, uint16_t *y,
466  const struct keypoint *points, int nbits)
467 {
468  const struct keypoint *point = points;
469  const int lut_size = 1<<nbits;
470  const int n = get_nb_points(points); // number of endpoints
471  double *xi, *fi, *di, *hi, *mi;
472  const int scale = lut_size - 1; // white value
473  uint16_t x; /* input index/value */
474  int ret = 0;
475 
476  /* no change for n = 0 or 1 */
477  if (n == 0) {
478  /* no points, no change */
479  for (int i = 0; i < lut_size; i++) y[i] = i;
480  return 0;
481  }
482 
483  if (n == 1) {
484  /* 1 point - 1 color everywhere */
485  const uint16_t yval = CLIP(point->y * scale);
486  for (int i = 0; i < lut_size; i++) y[i] = yval;
487  return 0;
488  }
489 
490  xi = av_calloc(3*n + 2*(n-1), sizeof(double)); /* output values at interval endpoints */
491  if (!xi) {
492  ret = AVERROR(ENOMEM);
493  goto end;
494  }
495 
496  fi = xi + n; /* output values at inteval endpoints */
497  di = fi + n; /* output slope wrt normalized input at interval endpoints */
498  hi = di + n; /* interval widths */
499  mi = hi + n - 1; /* linear slope over intervals */
500 
501  /* scale endpoints and store them in a contiguous memory block */
502  for (int i = 0; i < n; i++) {
503  xi[i] = point->x * scale;
504  fi[i] = point->y * scale;
505  point = point->next;
506  }
507 
508  /* h(i) = x(i+1) - x(i); mi(i) = (f(i+1)-f(i))/h(i) */
509  for (int i = 0; i < n - 1; i++) {
510  const double val = (xi[i+1]-xi[i]);
511  hi[i] = val;
512  mi[i] = (fi[i+1]-fi[i]) / val;
513  }
514 
515  if (n == 2) {
516  /* edge case, use linear interpolation */
517  const double m = mi[0], b = fi[0] - xi[0]*m;
518  for (int i = 0; i < lut_size; i++) y[i] = CLIP(i*m + b);
519  goto end;
520  }
521 
522  /* compute the derivatives at the endpoints*/
523  ret = pchip_find_derivatives(n-1, hi, mi, di);
524  if (ret)
525  goto end;
526 
527  /* interpolate/extrapolate */
528  x = 0;
529  if (xi[0] > 0) {
530  /* below first endpoint, use the first endpoint value*/
531  const double xi0 = xi[0];
532  const double yi0 = fi[0];
533  const uint16_t yval = CLIP(yi0);
534  for (; x < xi0; x++) {
535  y[x] = yval;
536  av_log(log_ctx, AV_LOG_TRACE, "f(%f)=%f -> y[%d]=%d\n", xi0, yi0, x, y[x]);
537  }
538  av_log(log_ctx, AV_LOG_DEBUG, "Interval -1: [0, %d] -> %d\n", x - 1, yval);
539  }
540 
541  /* for each interval */
542  for (int i = 0, x0 = x; i < n-1; i++, x0 = x) {
543  const double xi0 = xi[i]; /* start-of-interval input value */
544  const double xi1 = xi[i + 1]; /* end-of-interval input value */
545  const double h = hi[i]; /* interval width */
546  const double f0 = fi[i]; /* start-of-interval output value */
547  const double f1 = fi[i + 1]; /* end-of-interval output value */
548  const double d0 = di[i]; /* start-of-interval derivative */
549  const double d1 = di[i + 1]; /* end-of-interval derivative */
550 
551  /* fill the lut over the interval */
552  for (; x < xi1; x++) { /* safe not to check j < lut_size */
553  const double xx = (x - xi0) / h; /* normalize input */
554  const double yy = interp_cubic_hermite_half(1 - xx, f0, -h * d0)
555  + interp_cubic_hermite_half(xx, f1, h * d1);
556  y[x] = CLIP(yy);
557  av_log(log_ctx, AV_LOG_TRACE, "f(%f)=%f -> y[%d]=%d\n", xx, yy, x, y[x]);
558  }
559 
560  if (x > x0)
561  av_log(log_ctx, AV_LOG_DEBUG, "Interval %d: [%d, %d] -> [%d, %d]\n",
562  i, x0, x-1, y[x0], y[x-1]);
563  else
564  av_log(log_ctx, AV_LOG_DEBUG, "Interval %d: empty\n", i);
565  }
566 
567  if (x && x < lut_size) {
568  /* above the last endpoint, use the last endpoint value*/
569  const double xi1 = xi[n - 1];
570  const double yi1 = fi[n - 1];
571  const uint16_t yval = CLIP(yi1);
572  av_log(log_ctx, AV_LOG_DEBUG, "Interval %d: [%d, %d] -> %d\n",
573  n-1, x, lut_size - 1, yval);
574  for (; x && x < lut_size; x++) { /* loop until int overflow */
575  y[x] = yval;
576  av_log(log_ctx, AV_LOG_TRACE, "f(%f)=%f -> y[%d]=%d\n", xi1, yi1, x, yval);
577  }
578  }
579 
580 end:
581  av_free(xi);
582  return ret;
583 }
584 
585 
586 static int parse_psfile(AVFilterContext *ctx, const char *fname)
587 {
588  CurvesContext *curves = ctx->priv;
589  uint8_t *buf;
590  size_t size;
591  int i, ret, av_unused(version), nb_curves;
592  AVBPrint ptstr;
593  static const int comp_ids[] = {3, 0, 1, 2};
594 
596 
597  ret = av_file_map(fname, &buf, &size, 0, NULL);
598  if (ret < 0)
599  return ret;
600 
601 #define READ16(dst) do { \
602  if (size < 2) { \
603  ret = AVERROR_INVALIDDATA; \
604  goto end; \
605  } \
606  dst = AV_RB16(buf); \
607  buf += 2; \
608  size -= 2; \
609 } while (0)
610 
611  READ16(version);
612  READ16(nb_curves);
613  for (i = 0; i < FFMIN(nb_curves, FF_ARRAY_ELEMS(comp_ids)); i++) {
614  int nb_points, n;
615  av_bprint_clear(&ptstr);
616  READ16(nb_points);
617  for (n = 0; n < nb_points; n++) {
618  int y, x;
619  READ16(y);
620  READ16(x);
621  av_bprintf(&ptstr, "%f/%f ", x / 255., y / 255.);
622  }
623  if (*ptstr.str) {
624  char **pts = &curves->comp_points_str[comp_ids[i]];
625  if (!*pts) {
626  *pts = av_strdup(ptstr.str);
627  av_log(ctx, AV_LOG_DEBUG, "curves %d (intid=%d) [%d points]: [%s]\n",
628  i, comp_ids[i], nb_points, *pts);
629  if (!*pts) {
630  ret = AVERROR(ENOMEM);
631  goto end;
632  }
633  }
634  }
635  }
636 end:
637  av_bprint_finalize(&ptstr, NULL);
638  av_file_unmap(buf, size);
639  return ret;
640 }
641 
642 static int dump_curves(const char *fname, uint16_t *graph[NB_COMP + 1],
643  struct keypoint *comp_points[NB_COMP + 1],
644  int lut_size)
645 {
646  int i;
647  AVBPrint buf;
648  const double scale = 1. / (lut_size - 1);
649  static const char * const colors[] = { "red", "green", "blue", "#404040", };
650  FILE *f = avpriv_fopen_utf8(fname, "w");
651 
652  av_assert0(FF_ARRAY_ELEMS(colors) == NB_COMP + 1);
653 
654  if (!f) {
655  int ret = AVERROR(errno);
656  av_log(NULL, AV_LOG_ERROR, "Cannot open file '%s' for writing: %s\n",
657  fname, av_err2str(ret));
658  return ret;
659  }
660 
662 
663  av_bprintf(&buf, "set xtics 0.1\n");
664  av_bprintf(&buf, "set ytics 0.1\n");
665  av_bprintf(&buf, "set size square\n");
666  av_bprintf(&buf, "set grid\n");
667 
668  for (i = 0; i < FF_ARRAY_ELEMS(colors); i++) {
669  av_bprintf(&buf, "%s'-' using 1:2 with lines lc '%s' title ''",
670  i ? ", " : "plot ", colors[i]);
671  if (comp_points[i])
672  av_bprintf(&buf, ", '-' using 1:2 with points pointtype 3 lc '%s' title ''",
673  colors[i]);
674  }
675  av_bprintf(&buf, "\n");
676 
677  for (i = 0; i < FF_ARRAY_ELEMS(colors); i++) {
678  int x;
679 
680  /* plot generated values */
681  for (x = 0; x < lut_size; x++)
682  av_bprintf(&buf, "%f %f\n", x * scale, graph[i][x] * scale);
683  av_bprintf(&buf, "e\n");
684 
685  /* plot user knots */
686  if (comp_points[i]) {
687  const struct keypoint *point = comp_points[i];
688 
689  while (point) {
690  av_bprintf(&buf, "%f %f\n", point->x, point->y);
691  point = point->next;
692  }
693  av_bprintf(&buf, "e\n");
694  }
695  }
696 
697  fwrite(buf.str, 1, buf.len, f);
698  fclose(f);
699  av_bprint_finalize(&buf, NULL);
700  return 0;
701 }
702 
704 {
705  int i, ret;
706  CurvesContext *curves = ctx->priv;
707  char **pts = curves->comp_points_str;
708  const char *allp = curves->comp_points_str_all;
709 
710  //if (!allp && curves->preset != PRESET_NONE && curves_presets[curves->preset].all)
711  // allp = curves_presets[curves->preset].all;
712 
713  if (allp) {
714  for (i = 0; i < NB_COMP; i++) {
715  if (!pts[i])
716  pts[i] = av_strdup(allp);
717  if (!pts[i])
718  return AVERROR(ENOMEM);
719  }
720  }
721 
722  if (curves->psfile && !curves->parsed_psfile) {
723  ret = parse_psfile(ctx, curves->psfile);
724  if (ret < 0)
725  return ret;
726  curves->parsed_psfile = 1;
727  }
728 
729  if (curves->preset != PRESET_NONE) {
730 #define SET_COMP_IF_NOT_SET(n, name) do { \
731  if (!pts[n] && curves_presets[curves->preset].name) { \
732  pts[n] = av_strdup(curves_presets[curves->preset].name); \
733  if (!pts[n]) \
734  return AVERROR(ENOMEM); \
735  } \
736 } while (0)
741  curves->preset = PRESET_NONE;
742  }
743 
744  return 0;
745 }
746 
747 static int filter_slice_packed(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
748 {
749  int x, y;
750  const CurvesContext *curves = ctx->priv;
751  const ThreadData *td = arg;
752  const AVFrame *in = td->in;
753  const AVFrame *out = td->out;
754  const int direct = out == in;
755  const int step = curves->step;
756  const uint8_t r = curves->rgba_map[R];
757  const uint8_t g = curves->rgba_map[G];
758  const uint8_t b = curves->rgba_map[B];
759  const uint8_t a = curves->rgba_map[A];
760  const int slice_start = (in->height * jobnr ) / nb_jobs;
761  const int slice_end = (in->height * (jobnr+1)) / nb_jobs;
762 
763  if (curves->is_16bit) {
764  for (y = slice_start; y < slice_end; y++) {
765  uint16_t *dstp = ( uint16_t *)(out->data[0] + y * out->linesize[0]);
766  const uint16_t *srcp = (const uint16_t *)(in ->data[0] + y * in->linesize[0]);
767 
768  for (x = 0; x < in->width * step; x += step) {
769  dstp[x + r] = curves->graph[R][srcp[x + r]];
770  dstp[x + g] = curves->graph[G][srcp[x + g]];
771  dstp[x + b] = curves->graph[B][srcp[x + b]];
772  if (!direct && step == 4)
773  dstp[x + a] = srcp[x + a];
774  }
775  }
776  } else {
777  uint8_t *dst = out->data[0] + slice_start * out->linesize[0];
778  const uint8_t *src = in->data[0] + slice_start * in->linesize[0];
779 
780  for (y = slice_start; y < slice_end; y++) {
781  for (x = 0; x < in->width * step; x += step) {
782  dst[x + r] = curves->graph[R][src[x + r]];
783  dst[x + g] = curves->graph[G][src[x + g]];
784  dst[x + b] = curves->graph[B][src[x + b]];
785  if (!direct && step == 4)
786  dst[x + a] = src[x + a];
787  }
788  dst += out->linesize[0];
789  src += in ->linesize[0];
790  }
791  }
792  return 0;
793 }
794 
795 static int filter_slice_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
796 {
797  int x, y;
798  const CurvesContext *curves = ctx->priv;
799  const ThreadData *td = arg;
800  const AVFrame *in = td->in;
801  const AVFrame *out = td->out;
802  const int direct = out == in;
803  const int step = curves->step;
804  const uint8_t r = curves->rgba_map[R];
805  const uint8_t g = curves->rgba_map[G];
806  const uint8_t b = curves->rgba_map[B];
807  const uint8_t a = curves->rgba_map[A];
808  const int slice_start = (in->height * jobnr ) / nb_jobs;
809  const int slice_end = (in->height * (jobnr+1)) / nb_jobs;
810 
811  if (curves->is_16bit) {
812  for (y = slice_start; y < slice_end; y++) {
813  uint16_t *dstrp = ( uint16_t *)(out->data[r] + y * out->linesize[r]);
814  uint16_t *dstgp = ( uint16_t *)(out->data[g] + y * out->linesize[g]);
815  uint16_t *dstbp = ( uint16_t *)(out->data[b] + y * out->linesize[b]);
816  uint16_t *dstap = ( uint16_t *)(out->data[a] + y * out->linesize[a]);
817  const uint16_t *srcrp = (const uint16_t *)(in ->data[r] + y * in->linesize[r]);
818  const uint16_t *srcgp = (const uint16_t *)(in ->data[g] + y * in->linesize[g]);
819  const uint16_t *srcbp = (const uint16_t *)(in ->data[b] + y * in->linesize[b]);
820  const uint16_t *srcap = (const uint16_t *)(in ->data[a] + y * in->linesize[a]);
821 
822  for (x = 0; x < in->width; x++) {
823  dstrp[x] = curves->graph[R][srcrp[x]];
824  dstgp[x] = curves->graph[G][srcgp[x]];
825  dstbp[x] = curves->graph[B][srcbp[x]];
826  if (!direct && step == 4)
827  dstap[x] = srcap[x];
828  }
829  }
830  } else {
831  uint8_t *dstr = out->data[r] + slice_start * out->linesize[r];
832  uint8_t *dstg = out->data[g] + slice_start * out->linesize[g];
833  uint8_t *dstb = out->data[b] + slice_start * out->linesize[b];
834  uint8_t *dsta = out->data[a] + slice_start * out->linesize[a];
835  const uint8_t *srcr = in->data[r] + slice_start * in->linesize[r];
836  const uint8_t *srcg = in->data[g] + slice_start * in->linesize[g];
837  const uint8_t *srcb = in->data[b] + slice_start * in->linesize[b];
838  const uint8_t *srca = in->data[a] + slice_start * in->linesize[a];
839 
840  for (y = slice_start; y < slice_end; y++) {
841  for (x = 0; x < in->width; x++) {
842  dstr[x] = curves->graph[R][srcr[x]];
843  dstg[x] = curves->graph[G][srcg[x]];
844  dstb[x] = curves->graph[B][srcb[x]];
845  if (!direct && step == 4)
846  dsta[x] = srca[x];
847  }
848  dstr += out->linesize[r];
849  dstg += out->linesize[g];
850  dstb += out->linesize[b];
851  dsta += out->linesize[a];
852  srcr += in ->linesize[r];
853  srcg += in ->linesize[g];
854  srcb += in ->linesize[b];
855  srca += in ->linesize[a];
856  }
857  }
858  return 0;
859 }
860 
862 {
863  int i, j, ret;
864  AVFilterContext *ctx = inlink->dst;
865  CurvesContext *curves = ctx->priv;
867  char **pts = curves->comp_points_str;
868  struct keypoint *comp_points[NB_COMP + 1] = {0};
869 
870  ff_fill_rgba_map(curves->rgba_map, inlink->format);
871  curves->is_16bit = desc->comp[0].depth > 8;
872  curves->depth = desc->comp[0].depth;
873  curves->lut_size = 1 << curves->depth;
874  curves->step = av_get_padded_bits_per_pixel(desc) >> (3 + curves->is_16bit);
876 
877  for (i = 0; i < NB_COMP + 1; i++) {
878  if (!curves->graph[i])
879  curves->graph[i] = av_calloc(curves->lut_size, sizeof(*curves->graph[0]));
880  if (!curves->graph[i])
881  return AVERROR(ENOMEM);
882  ret = parse_points_str(ctx, comp_points + i, curves->comp_points_str[i], curves->lut_size);
883  if (ret < 0)
884  return ret;
885  if (curves->interp == INTERP_PCHIP)
886  ret = interpolate_pchip(ctx, curves->graph[i], comp_points[i], curves->depth);
887  else
888  ret = interpolate(ctx, curves->graph[i], comp_points[i], curves->depth);
889  if (ret < 0)
890  return ret;
891  }
892 
893  if (pts[NB_COMP]) {
894  for (i = 0; i < NB_COMP; i++)
895  for (j = 0; j < curves->lut_size; j++)
896  curves->graph[i][j] = curves->graph[NB_COMP][curves->graph[i][j]];
897  }
898 
899  if (av_log_get_level() >= AV_LOG_VERBOSE) {
900  for (i = 0; i < NB_COMP; i++) {
901  const struct keypoint *point = comp_points[i];
902  av_log(ctx, AV_LOG_VERBOSE, "#%d points:", i);
903  while (point) {
904  av_log(ctx, AV_LOG_VERBOSE, " (%f;%f)", point->x, point->y);
905  point = point->next;
906  }
907  }
908  }
909 
910  if (curves->plot_filename && !curves->saved_plot) {
911  dump_curves(curves->plot_filename, curves->graph, comp_points, curves->lut_size);
912  curves->saved_plot = 1;
913  }
914 
915  for (i = 0; i < NB_COMP + 1; i++) {
916  struct keypoint *point = comp_points[i];
917  while (point) {
918  struct keypoint *next = point->next;
919  av_free(point);
920  point = next;
921  }
922  }
923 
924  return 0;
925 }
926 
928 {
929  AVFilterContext *ctx = inlink->dst;
930  CurvesContext *curves = ctx->priv;
931  AVFilterLink *outlink = ctx->outputs[0];
932  AVFrame *out;
933  ThreadData td;
934 
935  if (av_frame_is_writable(in)) {
936  out = in;
937  } else {
938  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
939  if (!out) {
940  av_frame_free(&in);
941  return AVERROR(ENOMEM);
942  }
944  }
945 
946  td.in = in;
947  td.out = out;
948  ff_filter_execute(ctx, curves->filter_slice, &td, NULL,
949  FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
950 
951  if (out != in)
952  av_frame_free(&in);
953 
954  return ff_filter_frame(outlink, out);
955 }
956 
957 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
958  char *res, int res_len, int flags)
959 {
960  CurvesContext *curves = ctx->priv;
961  int ret;
962 
963  if (!strcmp(cmd, "plot")) {
964  curves->saved_plot = 0;
965  } else if (!strcmp(cmd, "all") || !strcmp(cmd, "preset") || !strcmp(cmd, "psfile") || !strcmp(cmd, "interp")) {
966  if (!strcmp(cmd, "psfile"))
967  curves->parsed_psfile = 0;
968  av_freep(&curves->comp_points_str_all);
969  av_freep(&curves->comp_points_str[0]);
970  av_freep(&curves->comp_points_str[1]);
971  av_freep(&curves->comp_points_str[2]);
972  av_freep(&curves->comp_points_str[NB_COMP]);
973  } else if (!strcmp(cmd, "red") || !strcmp(cmd, "r")) {
974  av_freep(&curves->comp_points_str[0]);
975  } else if (!strcmp(cmd, "green") || !strcmp(cmd, "g")) {
976  av_freep(&curves->comp_points_str[1]);
977  } else if (!strcmp(cmd, "blue") || !strcmp(cmd, "b")) {
978  av_freep(&curves->comp_points_str[2]);
979  } else if (!strcmp(cmd, "master") || !strcmp(cmd, "m")) {
980  av_freep(&curves->comp_points_str[NB_COMP]);
981  }
982 
983  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
984  if (ret < 0)
985  return ret;
986 
987  ret = curves_init(ctx);
988  if (ret < 0)
989  return ret;
990  return config_input(ctx->inputs[0]);
991 }
992 
994 {
995  int i;
996  CurvesContext *curves = ctx->priv;
997 
998  for (i = 0; i < NB_COMP + 1; i++)
999  av_freep(&curves->graph[i]);
1000 }
1001 
1002 static const AVFilterPad curves_inputs[] = {
1003  {
1004  .name = "default",
1005  .type = AVMEDIA_TYPE_VIDEO,
1006  .filter_frame = filter_frame,
1007  .config_props = config_input,
1008  },
1009 };
1010 
1012  .name = "curves",
1013  .description = NULL_IF_CONFIG_SMALL("Adjust components curves."),
1014  .priv_size = sizeof(CurvesContext),
1015  .init = curves_init,
1016  .uninit = curves_uninit,
1032  .priv_class = &curves_class,
1034  .process_command = process_command,
1035 };
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
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:642
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:444
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:357
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:1002
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:214
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
slice_end
static int slice_end(AVCodecContext *avctx, AVFrame *pict, int *got_output)
Handle slice ends.
Definition: mpeg12dec.c:1747
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:957
mi
#define mi
Definition: vf_colormatrix.c:106
g
const char * g
Definition: vf_curves.c:128
keypoint
Definition: vf_curves.c:40
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:230
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
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:232
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
curves_presets
static const struct @313 curves_presets[]
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:122
ff_vf_curves
const AVFilter ff_vf_curves
Definition: vf_curves.c:1011
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:993
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:795
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:747
CurvesContext::plot_filename
char * plot_filename
Definition: vf_curves.c:78
SIGN
#define SIGN(x)
Definition: vf_curves.c:355
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:245
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:400
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:700
config_input
static int config_input(AVFilterLink *inlink)
Definition: vf_curves.c:861
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:79
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:703
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:465
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:586
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:371
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:249
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:254
OFFSET
#define OFFSET(x)
Definition: vf_curves.c:92
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_curves.c:927