FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vf_lut3d.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Clément Bœsch
3  * Copyright (c) 2018 Paul B Mahol
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /**
23  * @file
24  * 3D Lookup table filter
25  */
26 
27 #include "libavutil/opt.h"
28 #include "libavutil/file.h"
29 #include "libavutil/intreadwrite.h"
30 #include "libavutil/avassert.h"
31 #include "libavutil/pixdesc.h"
32 #include "libavutil/avstring.h"
33 #include "avfilter.h"
34 #include "drawutils.h"
35 #include "formats.h"
36 #include "framesync.h"
37 #include "internal.h"
38 #include "video.h"
39 
40 #define R 0
41 #define G 1
42 #define B 2
43 #define A 3
44 
50 };
51 
52 struct rgbvec {
53  float r, g, b;
54 };
55 
56 /* 3D LUT don't often go up to level 32, but it is common to have a Hald CLUT
57  * of 512x512 (64x64x64) */
58 #define MAX_LEVEL 64
59 
60 typedef struct LUT3DContext {
61  const AVClass *class;
62  int interpolation; ///<interp_mode
63  char *file;
65  int step;
68  int lutsize;
69 #if CONFIG_HALDCLUT_FILTER
70  uint8_t clut_rgba_map[4];
71  int clut_step;
72  int clut_bits;
73  int clut_planar;
74  int clut_width;
76 #endif
77 } LUT3DContext;
78 
79 typedef struct ThreadData {
80  AVFrame *in, *out;
81 } ThreadData;
82 
83 #define OFFSET(x) offsetof(LUT3DContext, x)
84 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
85 #define COMMON_OPTIONS \
86  { "interp", "select interpolation mode", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=INTERPOLATE_TETRAHEDRAL}, 0, NB_INTERP_MODE-1, FLAGS, "interp_mode" }, \
87  { "nearest", "use values from the nearest defined points", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_NEAREST}, INT_MIN, INT_MAX, FLAGS, "interp_mode" }, \
88  { "trilinear", "interpolate values using the 8 points defining a cube", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_TRILINEAR}, INT_MIN, INT_MAX, FLAGS, "interp_mode" }, \
89  { "tetrahedral", "interpolate values using a tetrahedron", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_TETRAHEDRAL}, INT_MIN, INT_MAX, FLAGS, "interp_mode" }, \
90  { NULL }
91 
92 static inline float lerpf(float v0, float v1, float f)
93 {
94  return v0 + (v1 - v0) * f;
95 }
96 
97 static inline struct rgbvec lerp(const struct rgbvec *v0, const struct rgbvec *v1, float f)
98 {
99  struct rgbvec v = {
100  lerpf(v0->r, v1->r, f), lerpf(v0->g, v1->g, f), lerpf(v0->b, v1->b, f)
101  };
102  return v;
103 }
104 
105 #define NEAR(x) ((int)((x) + .5))
106 #define PREV(x) ((int)(x))
107 #define NEXT(x) (FFMIN((int)(x) + 1, lut3d->lutsize - 1))
108 
109 /**
110  * Get the nearest defined point
111  */
112 static inline struct rgbvec interp_nearest(const LUT3DContext *lut3d,
113  const struct rgbvec *s)
114 {
115  return lut3d->lut[NEAR(s->r)][NEAR(s->g)][NEAR(s->b)];
116 }
117 
118 /**
119  * Interpolate using the 8 vertices of a cube
120  * @see https://en.wikipedia.org/wiki/Trilinear_interpolation
121  */
122 static inline struct rgbvec interp_trilinear(const LUT3DContext *lut3d,
123  const struct rgbvec *s)
124 {
125  const int prev[] = {PREV(s->r), PREV(s->g), PREV(s->b)};
126  const int next[] = {NEXT(s->r), NEXT(s->g), NEXT(s->b)};
127  const struct rgbvec d = {s->r - prev[0], s->g - prev[1], s->b - prev[2]};
128  const struct rgbvec c000 = lut3d->lut[prev[0]][prev[1]][prev[2]];
129  const struct rgbvec c001 = lut3d->lut[prev[0]][prev[1]][next[2]];
130  const struct rgbvec c010 = lut3d->lut[prev[0]][next[1]][prev[2]];
131  const struct rgbvec c011 = lut3d->lut[prev[0]][next[1]][next[2]];
132  const struct rgbvec c100 = lut3d->lut[next[0]][prev[1]][prev[2]];
133  const struct rgbvec c101 = lut3d->lut[next[0]][prev[1]][next[2]];
134  const struct rgbvec c110 = lut3d->lut[next[0]][next[1]][prev[2]];
135  const struct rgbvec c111 = lut3d->lut[next[0]][next[1]][next[2]];
136  const struct rgbvec c00 = lerp(&c000, &c100, d.r);
137  const struct rgbvec c10 = lerp(&c010, &c110, d.r);
138  const struct rgbvec c01 = lerp(&c001, &c101, d.r);
139  const struct rgbvec c11 = lerp(&c011, &c111, d.r);
140  const struct rgbvec c0 = lerp(&c00, &c10, d.g);
141  const struct rgbvec c1 = lerp(&c01, &c11, d.g);
142  const struct rgbvec c = lerp(&c0, &c1, d.b);
143  return c;
144 }
145 
146 /**
147  * Tetrahedral interpolation. Based on code found in Truelight Software Library paper.
148  * @see http://www.filmlight.ltd.uk/pdf/whitepapers/FL-TL-TN-0057-SoftwareLib.pdf
149  */
150 static inline struct rgbvec interp_tetrahedral(const LUT3DContext *lut3d,
151  const struct rgbvec *s)
152 {
153  const int prev[] = {PREV(s->r), PREV(s->g), PREV(s->b)};
154  const int next[] = {NEXT(s->r), NEXT(s->g), NEXT(s->b)};
155  const struct rgbvec d = {s->r - prev[0], s->g - prev[1], s->b - prev[2]};
156  const struct rgbvec c000 = lut3d->lut[prev[0]][prev[1]][prev[2]];
157  const struct rgbvec c111 = lut3d->lut[next[0]][next[1]][next[2]];
158  struct rgbvec c;
159  if (d.r > d.g) {
160  if (d.g > d.b) {
161  const struct rgbvec c100 = lut3d->lut[next[0]][prev[1]][prev[2]];
162  const struct rgbvec c110 = lut3d->lut[next[0]][next[1]][prev[2]];
163  c.r = (1-d.r) * c000.r + (d.r-d.g) * c100.r + (d.g-d.b) * c110.r + (d.b) * c111.r;
164  c.g = (1-d.r) * c000.g + (d.r-d.g) * c100.g + (d.g-d.b) * c110.g + (d.b) * c111.g;
165  c.b = (1-d.r) * c000.b + (d.r-d.g) * c100.b + (d.g-d.b) * c110.b + (d.b) * c111.b;
166  } else if (d.r > d.b) {
167  const struct rgbvec c100 = lut3d->lut[next[0]][prev[1]][prev[2]];
168  const struct rgbvec c101 = lut3d->lut[next[0]][prev[1]][next[2]];
169  c.r = (1-d.r) * c000.r + (d.r-d.b) * c100.r + (d.b-d.g) * c101.r + (d.g) * c111.r;
170  c.g = (1-d.r) * c000.g + (d.r-d.b) * c100.g + (d.b-d.g) * c101.g + (d.g) * c111.g;
171  c.b = (1-d.r) * c000.b + (d.r-d.b) * c100.b + (d.b-d.g) * c101.b + (d.g) * c111.b;
172  } else {
173  const struct rgbvec c001 = lut3d->lut[prev[0]][prev[1]][next[2]];
174  const struct rgbvec c101 = lut3d->lut[next[0]][prev[1]][next[2]];
175  c.r = (1-d.b) * c000.r + (d.b-d.r) * c001.r + (d.r-d.g) * c101.r + (d.g) * c111.r;
176  c.g = (1-d.b) * c000.g + (d.b-d.r) * c001.g + (d.r-d.g) * c101.g + (d.g) * c111.g;
177  c.b = (1-d.b) * c000.b + (d.b-d.r) * c001.b + (d.r-d.g) * c101.b + (d.g) * c111.b;
178  }
179  } else {
180  if (d.b > d.g) {
181  const struct rgbvec c001 = lut3d->lut[prev[0]][prev[1]][next[2]];
182  const struct rgbvec c011 = lut3d->lut[prev[0]][next[1]][next[2]];
183  c.r = (1-d.b) * c000.r + (d.b-d.g) * c001.r + (d.g-d.r) * c011.r + (d.r) * c111.r;
184  c.g = (1-d.b) * c000.g + (d.b-d.g) * c001.g + (d.g-d.r) * c011.g + (d.r) * c111.g;
185  c.b = (1-d.b) * c000.b + (d.b-d.g) * c001.b + (d.g-d.r) * c011.b + (d.r) * c111.b;
186  } else if (d.b > d.r) {
187  const struct rgbvec c010 = lut3d->lut[prev[0]][next[1]][prev[2]];
188  const struct rgbvec c011 = lut3d->lut[prev[0]][next[1]][next[2]];
189  c.r = (1-d.g) * c000.r + (d.g-d.b) * c010.r + (d.b-d.r) * c011.r + (d.r) * c111.r;
190  c.g = (1-d.g) * c000.g + (d.g-d.b) * c010.g + (d.b-d.r) * c011.g + (d.r) * c111.g;
191  c.b = (1-d.g) * c000.b + (d.g-d.b) * c010.b + (d.b-d.r) * c011.b + (d.r) * c111.b;
192  } else {
193  const struct rgbvec c010 = lut3d->lut[prev[0]][next[1]][prev[2]];
194  const struct rgbvec c110 = lut3d->lut[next[0]][next[1]][prev[2]];
195  c.r = (1-d.g) * c000.r + (d.g-d.r) * c010.r + (d.r-d.b) * c110.r + (d.b) * c111.r;
196  c.g = (1-d.g) * c000.g + (d.g-d.r) * c010.g + (d.r-d.b) * c110.g + (d.b) * c111.g;
197  c.b = (1-d.g) * c000.b + (d.g-d.r) * c010.b + (d.r-d.b) * c110.b + (d.b) * c111.b;
198  }
199  }
200  return c;
201 }
202 
203 #define DEFINE_INTERP_FUNC_PLANAR(name, nbits, depth) \
204 static int interp_##nbits##_##name##_p##depth(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
205 { \
206  int x, y; \
207  const LUT3DContext *lut3d = ctx->priv; \
208  const ThreadData *td = arg; \
209  const AVFrame *in = td->in; \
210  const AVFrame *out = td->out; \
211  const int direct = out == in; \
212  const int slice_start = (in->height * jobnr ) / nb_jobs; \
213  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
214  uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
215  uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
216  uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
217  uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
218  const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
219  const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
220  const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
221  const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
222  const float scale = (1. / ((1<<depth) - 1)) * (lut3d->lutsize - 1); \
223  \
224  for (y = slice_start; y < slice_end; y++) { \
225  uint##nbits##_t *dstg = (uint##nbits##_t *)grow; \
226  uint##nbits##_t *dstb = (uint##nbits##_t *)brow; \
227  uint##nbits##_t *dstr = (uint##nbits##_t *)rrow; \
228  uint##nbits##_t *dsta = (uint##nbits##_t *)arow; \
229  const uint##nbits##_t *srcg = (const uint##nbits##_t *)srcgrow; \
230  const uint##nbits##_t *srcb = (const uint##nbits##_t *)srcbrow; \
231  const uint##nbits##_t *srcr = (const uint##nbits##_t *)srcrrow; \
232  const uint##nbits##_t *srca = (const uint##nbits##_t *)srcarow; \
233  for (x = 0; x < in->width; x++) { \
234  const struct rgbvec scaled_rgb = {srcr[x] * scale, \
235  srcg[x] * scale, \
236  srcb[x] * scale}; \
237  struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \
238  dstr[x] = av_clip_uintp2(vec.r * (float)((1<<depth) - 1), depth); \
239  dstg[x] = av_clip_uintp2(vec.g * (float)((1<<depth) - 1), depth); \
240  dstb[x] = av_clip_uintp2(vec.b * (float)((1<<depth) - 1), depth); \
241  if (!direct && in->linesize[3]) \
242  dsta[x] = srca[x]; \
243  } \
244  grow += out->linesize[0]; \
245  brow += out->linesize[1]; \
246  rrow += out->linesize[2]; \
247  arow += out->linesize[3]; \
248  srcgrow += in->linesize[0]; \
249  srcbrow += in->linesize[1]; \
250  srcrrow += in->linesize[2]; \
251  srcarow += in->linesize[3]; \
252  } \
253  return 0; \
254 }
255 
256 DEFINE_INTERP_FUNC_PLANAR(nearest, 8, 8)
257 DEFINE_INTERP_FUNC_PLANAR(trilinear, 8, 8)
258 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 8, 8)
259 
260 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 9)
261 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 9)
262 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 9)
263 
264 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 10)
265 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 10)
266 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 10)
267 
268 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 12)
269 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 12)
270 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 12)
271 
272 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 14)
273 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 14)
274 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 14)
275 
276 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 16)
277 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 16)
278 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 16)
279 
280 #define DEFINE_INTERP_FUNC(name, nbits) \
281 static int interp_##nbits##_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
282 { \
283  int x, y; \
284  const LUT3DContext *lut3d = ctx->priv; \
285  const ThreadData *td = arg; \
286  const AVFrame *in = td->in; \
287  const AVFrame *out = td->out; \
288  const int direct = out == in; \
289  const int step = lut3d->step; \
290  const uint8_t r = lut3d->rgba_map[R]; \
291  const uint8_t g = lut3d->rgba_map[G]; \
292  const uint8_t b = lut3d->rgba_map[B]; \
293  const uint8_t a = lut3d->rgba_map[A]; \
294  const int slice_start = (in->height * jobnr ) / nb_jobs; \
295  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
296  uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \
297  const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \
298  const float scale = (1. / ((1<<nbits) - 1)) * (lut3d->lutsize - 1); \
299  \
300  for (y = slice_start; y < slice_end; y++) { \
301  uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \
302  const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \
303  for (x = 0; x < in->width * step; x += step) { \
304  const struct rgbvec scaled_rgb = {src[x + r] * scale, \
305  src[x + g] * scale, \
306  src[x + b] * scale}; \
307  struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \
308  dst[x + r] = av_clip_uint##nbits(vec.r * (float)((1<<nbits) - 1)); \
309  dst[x + g] = av_clip_uint##nbits(vec.g * (float)((1<<nbits) - 1)); \
310  dst[x + b] = av_clip_uint##nbits(vec.b * (float)((1<<nbits) - 1)); \
311  if (!direct && step == 4) \
312  dst[x + a] = src[x + a]; \
313  } \
314  dstrow += out->linesize[0]; \
315  srcrow += in ->linesize[0]; \
316  } \
317  return 0; \
318 }
319 
320 DEFINE_INTERP_FUNC(nearest, 8)
321 DEFINE_INTERP_FUNC(trilinear, 8)
322 DEFINE_INTERP_FUNC(tetrahedral, 8)
323 
324 DEFINE_INTERP_FUNC(nearest, 16)
325 DEFINE_INTERP_FUNC(trilinear, 16)
326 DEFINE_INTERP_FUNC(tetrahedral, 16)
327 
328 #define MAX_LINE_SIZE 512
329 
330 static int skip_line(const char *p)
331 {
332  while (*p && av_isspace(*p))
333  p++;
334  return !*p || *p == '#';
335 }
336 
337 #define NEXT_LINE(loop_cond) do { \
338  if (!fgets(line, sizeof(line), f)) { \
339  av_log(ctx, AV_LOG_ERROR, "Unexpected EOF\n"); \
340  return AVERROR_INVALIDDATA; \
341  } \
342 } while (loop_cond)
343 
344 /* Basically r g and b float values on each line, with a facultative 3DLUTSIZE
345  * directive; seems to be generated by Davinci */
346 static int parse_dat(AVFilterContext *ctx, FILE *f)
347 {
348  LUT3DContext *lut3d = ctx->priv;
349  char line[MAX_LINE_SIZE];
350  int i, j, k, size;
351 
352  lut3d->lutsize = size = 33;
353 
354  NEXT_LINE(skip_line(line));
355  if (!strncmp(line, "3DLUTSIZE ", 10)) {
356  size = strtol(line + 10, NULL, 0);
358  av_log(ctx, AV_LOG_ERROR, "Too large or invalid 3D LUT size\n");
359  return AVERROR(EINVAL);
360  }
361  lut3d->lutsize = size;
362  NEXT_LINE(skip_line(line));
363  }
364  for (k = 0; k < size; k++) {
365  for (j = 0; j < size; j++) {
366  for (i = 0; i < size; i++) {
367  struct rgbvec *vec = &lut3d->lut[k][j][i];
368  if (k != 0 || j != 0 || i != 0)
369  NEXT_LINE(skip_line(line));
370  if (sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3)
371  return AVERROR_INVALIDDATA;
372  }
373  }
374  }
375  return 0;
376 }
377 
378 /* Iridas format */
379 static int parse_cube(AVFilterContext *ctx, FILE *f)
380 {
381  LUT3DContext *lut3d = ctx->priv;
382  char line[MAX_LINE_SIZE];
383  float min[3] = {0.0, 0.0, 0.0};
384  float max[3] = {1.0, 1.0, 1.0};
385 
386  while (fgets(line, sizeof(line), f)) {
387  if (!strncmp(line, "LUT_3D_SIZE ", 12)) {
388  int i, j, k;
389  const int size = strtol(line + 12, NULL, 0);
390 
392  av_log(ctx, AV_LOG_ERROR, "Too large or invalid 3D LUT size\n");
393  return AVERROR(EINVAL);
394  }
395  lut3d->lutsize = size;
396  for (k = 0; k < size; k++) {
397  for (j = 0; j < size; j++) {
398  for (i = 0; i < size; i++) {
399  struct rgbvec *vec = &lut3d->lut[i][j][k];
400 
401  do {
402 try_again:
403  NEXT_LINE(0);
404  if (!strncmp(line, "DOMAIN_", 7)) {
405  float *vals = NULL;
406  if (!strncmp(line + 7, "MIN ", 4)) vals = min;
407  else if (!strncmp(line + 7, "MAX ", 4)) vals = max;
408  if (!vals)
409  return AVERROR_INVALIDDATA;
410  sscanf(line + 11, "%f %f %f", vals, vals + 1, vals + 2);
411  av_log(ctx, AV_LOG_DEBUG, "min: %f %f %f | max: %f %f %f\n",
412  min[0], min[1], min[2], max[0], max[1], max[2]);
413  goto try_again;
414  } else if (!strncmp(line, "TITLE", 5)) {
415  goto try_again;
416  }
417  } while (skip_line(line));
418  if (sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3)
419  return AVERROR_INVALIDDATA;
420  vec->r *= max[0] - min[0];
421  vec->g *= max[1] - min[1];
422  vec->b *= max[2] - min[2];
423  }
424  }
425  }
426  break;
427  }
428  }
429  return 0;
430 }
431 
432 /* Assume 17x17x17 LUT with a 16-bit depth
433  * FIXME: it seems there are various 3dl formats */
434 static int parse_3dl(AVFilterContext *ctx, FILE *f)
435 {
436  char line[MAX_LINE_SIZE];
437  LUT3DContext *lut3d = ctx->priv;
438  int i, j, k;
439  const int size = 17;
440  const float scale = 16*16*16;
441 
442  lut3d->lutsize = size;
443  NEXT_LINE(skip_line(line));
444  for (k = 0; k < size; k++) {
445  for (j = 0; j < size; j++) {
446  for (i = 0; i < size; i++) {
447  int r, g, b;
448  struct rgbvec *vec = &lut3d->lut[k][j][i];
449 
450  NEXT_LINE(skip_line(line));
451  if (sscanf(line, "%d %d %d", &r, &g, &b) != 3)
452  return AVERROR_INVALIDDATA;
453  vec->r = r / scale;
454  vec->g = g / scale;
455  vec->b = b / scale;
456  }
457  }
458  }
459  return 0;
460 }
461 
462 /* Pandora format */
463 static int parse_m3d(AVFilterContext *ctx, FILE *f)
464 {
465  LUT3DContext *lut3d = ctx->priv;
466  float scale;
467  int i, j, k, size, in = -1, out = -1;
468  char line[MAX_LINE_SIZE];
469  uint8_t rgb_map[3] = {0, 1, 2};
470 
471  while (fgets(line, sizeof(line), f)) {
472  if (!strncmp(line, "in", 2)) in = strtol(line + 2, NULL, 0);
473  else if (!strncmp(line, "out", 3)) out = strtol(line + 3, NULL, 0);
474  else if (!strncmp(line, "values", 6)) {
475  const char *p = line + 6;
476 #define SET_COLOR(id) do { \
477  while (av_isspace(*p)) \
478  p++; \
479  switch (*p) { \
480  case 'r': rgb_map[id] = 0; break; \
481  case 'g': rgb_map[id] = 1; break; \
482  case 'b': rgb_map[id] = 2; break; \
483  } \
484  while (*p && !av_isspace(*p)) \
485  p++; \
486 } while (0)
487  SET_COLOR(0);
488  SET_COLOR(1);
489  SET_COLOR(2);
490  break;
491  }
492  }
493 
494  if (in == -1 || out == -1) {
495  av_log(ctx, AV_LOG_ERROR, "in and out must be defined\n");
496  return AVERROR_INVALIDDATA;
497  }
498  if (in < 2 || out < 2 ||
501  av_log(ctx, AV_LOG_ERROR, "invalid in (%d) or out (%d)\n", in, out);
502  return AVERROR_INVALIDDATA;
503  }
504  for (size = 1; size*size*size < in; size++);
505  lut3d->lutsize = size;
506  scale = 1. / (out - 1);
507 
508  for (k = 0; k < size; k++) {
509  for (j = 0; j < size; j++) {
510  for (i = 0; i < size; i++) {
511  struct rgbvec *vec = &lut3d->lut[k][j][i];
512  float val[3];
513 
514  NEXT_LINE(0);
515  if (sscanf(line, "%f %f %f", val, val + 1, val + 2) != 3)
516  return AVERROR_INVALIDDATA;
517  vec->r = val[rgb_map[0]] * scale;
518  vec->g = val[rgb_map[1]] * scale;
519  vec->b = val[rgb_map[2]] * scale;
520  }
521  }
522  }
523  return 0;
524 }
525 
526 static void set_identity_matrix(LUT3DContext *lut3d, int size)
527 {
528  int i, j, k;
529  const float c = 1. / (size - 1);
530 
531  lut3d->lutsize = size;
532  for (k = 0; k < size; k++) {
533  for (j = 0; j < size; j++) {
534  for (i = 0; i < size; i++) {
535  struct rgbvec *vec = &lut3d->lut[k][j][i];
536  vec->r = k * c;
537  vec->g = j * c;
538  vec->b = i * c;
539  }
540  }
541  }
542 }
543 
545 {
546  static const enum AVPixelFormat pix_fmts[] = {
561  };
562  AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
563  if (!fmts_list)
564  return AVERROR(ENOMEM);
565  return ff_set_common_formats(ctx, fmts_list);
566 }
567 
568 static int config_input(AVFilterLink *inlink)
569 {
570  int depth, is16bit = 0, planar = 0;
571  LUT3DContext *lut3d = inlink->dst->priv;
573 
574  depth = desc->comp[0].depth;
575 
576  switch (inlink->format) {
577  case AV_PIX_FMT_RGB48:
578  case AV_PIX_FMT_BGR48:
579  case AV_PIX_FMT_RGBA64:
580  case AV_PIX_FMT_BGRA64:
581  is16bit = 1;
582  break;
583  case AV_PIX_FMT_GBRP9:
584  case AV_PIX_FMT_GBRP10:
585  case AV_PIX_FMT_GBRP12:
586  case AV_PIX_FMT_GBRP14:
587  case AV_PIX_FMT_GBRP16:
588  case AV_PIX_FMT_GBRAP10:
589  case AV_PIX_FMT_GBRAP12:
590  case AV_PIX_FMT_GBRAP16:
591  is16bit = 1;
592  case AV_PIX_FMT_GBRP:
593  case AV_PIX_FMT_GBRAP:
594  planar = 1;
595  break;
596  }
597 
598  ff_fill_rgba_map(lut3d->rgba_map, inlink->format);
599  lut3d->step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit);
600 
601 #define SET_FUNC(name) do { \
602  if (planar) { \
603  switch (depth) { \
604  case 8: lut3d->interp = interp_8_##name##_p8; break; \
605  case 9: lut3d->interp = interp_16_##name##_p9; break; \
606  case 10: lut3d->interp = interp_16_##name##_p10; break; \
607  case 12: lut3d->interp = interp_16_##name##_p12; break; \
608  case 14: lut3d->interp = interp_16_##name##_p14; break; \
609  case 16: lut3d->interp = interp_16_##name##_p16; break; \
610  } \
611  } else if (is16bit) { lut3d->interp = interp_16_##name; \
612  } else { lut3d->interp = interp_8_##name; } \
613 } while (0)
614 
615  switch (lut3d->interpolation) {
616  case INTERPOLATE_NEAREST: SET_FUNC(nearest); break;
617  case INTERPOLATE_TRILINEAR: SET_FUNC(trilinear); break;
618  case INTERPOLATE_TETRAHEDRAL: SET_FUNC(tetrahedral); break;
619  default:
620  av_assert0(0);
621  }
622 
623  return 0;
624 }
625 
627 {
628  AVFilterContext *ctx = inlink->dst;
629  LUT3DContext *lut3d = ctx->priv;
630  AVFilterLink *outlink = inlink->dst->outputs[0];
631  AVFrame *out;
632  ThreadData td;
633 
634  if (av_frame_is_writable(in)) {
635  out = in;
636  } else {
637  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
638  if (!out) {
639  av_frame_free(&in);
640  return NULL;
641  }
642  av_frame_copy_props(out, in);
643  }
644 
645  td.in = in;
646  td.out = out;
647  ctx->internal->execute(ctx, lut3d->interp, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
648 
649  if (out != in)
650  av_frame_free(&in);
651 
652  return out;
653 }
654 
655 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
656 {
657  AVFilterLink *outlink = inlink->dst->outputs[0];
658  AVFrame *out = apply_lut(inlink, in);
659  if (!out)
660  return AVERROR(ENOMEM);
661  return ff_filter_frame(outlink, out);
662 }
663 
664 #if CONFIG_LUT3D_FILTER
665 static const AVOption lut3d_options[] = {
666  { "file", "set 3D LUT file name", OFFSET(file), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
668 };
669 
670 AVFILTER_DEFINE_CLASS(lut3d);
671 
672 static av_cold int lut3d_init(AVFilterContext *ctx)
673 {
674  int ret;
675  FILE *f;
676  const char *ext;
677  LUT3DContext *lut3d = ctx->priv;
678 
679  if (!lut3d->file) {
680  set_identity_matrix(lut3d, 32);
681  return 0;
682  }
683 
684  f = fopen(lut3d->file, "r");
685  if (!f) {
686  ret = AVERROR(errno);
687  av_log(ctx, AV_LOG_ERROR, "%s: %s\n", lut3d->file, av_err2str(ret));
688  return ret;
689  }
690 
691  ext = strrchr(lut3d->file, '.');
692  if (!ext) {
693  av_log(ctx, AV_LOG_ERROR, "Unable to guess the format from the extension\n");
694  ret = AVERROR_INVALIDDATA;
695  goto end;
696  }
697  ext++;
698 
699  if (!av_strcasecmp(ext, "dat")) {
700  ret = parse_dat(ctx, f);
701  } else if (!av_strcasecmp(ext, "3dl")) {
702  ret = parse_3dl(ctx, f);
703  } else if (!av_strcasecmp(ext, "cube")) {
704  ret = parse_cube(ctx, f);
705  } else if (!av_strcasecmp(ext, "m3d")) {
706  ret = parse_m3d(ctx, f);
707  } else {
708  av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext);
709  ret = AVERROR(EINVAL);
710  }
711 
712  if (!ret && !lut3d->lutsize) {
713  av_log(ctx, AV_LOG_ERROR, "3D LUT is empty\n");
714  ret = AVERROR_INVALIDDATA;
715  }
716 
717 end:
718  fclose(f);
719  return ret;
720 }
721 
722 static const AVFilterPad lut3d_inputs[] = {
723  {
724  .name = "default",
725  .type = AVMEDIA_TYPE_VIDEO,
726  .filter_frame = filter_frame,
727  .config_props = config_input,
728  },
729  { NULL }
730 };
731 
732 static const AVFilterPad lut3d_outputs[] = {
733  {
734  .name = "default",
735  .type = AVMEDIA_TYPE_VIDEO,
736  },
737  { NULL }
738 };
739 
741  .name = "lut3d",
742  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a 3D LUT."),
743  .priv_size = sizeof(LUT3DContext),
744  .init = lut3d_init,
746  .inputs = lut3d_inputs,
747  .outputs = lut3d_outputs,
748  .priv_class = &lut3d_class,
750 };
751 #endif
752 
753 #if CONFIG_HALDCLUT_FILTER
754 
755 static void update_clut_packed(LUT3DContext *lut3d, const AVFrame *frame)
756 {
757  const uint8_t *data = frame->data[0];
758  const int linesize = frame->linesize[0];
759  const int w = lut3d->clut_width;
760  const int step = lut3d->clut_step;
761  const uint8_t *rgba_map = lut3d->clut_rgba_map;
762  const int level = lut3d->lutsize;
763 
764 #define LOAD_CLUT(nbits) do { \
765  int i, j, k, x = 0, y = 0; \
766  \
767  for (k = 0; k < level; k++) { \
768  for (j = 0; j < level; j++) { \
769  for (i = 0; i < level; i++) { \
770  const uint##nbits##_t *src = (const uint##nbits##_t *) \
771  (data + y*linesize + x*step); \
772  struct rgbvec *vec = &lut3d->lut[i][j][k]; \
773  vec->r = src[rgba_map[0]] / (float)((1<<(nbits)) - 1); \
774  vec->g = src[rgba_map[1]] / (float)((1<<(nbits)) - 1); \
775  vec->b = src[rgba_map[2]] / (float)((1<<(nbits)) - 1); \
776  if (++x == w) { \
777  x = 0; \
778  y++; \
779  } \
780  } \
781  } \
782  } \
783 } while (0)
784 
785  switch (lut3d->clut_bits) {
786  case 8: LOAD_CLUT(8); break;
787  case 16: LOAD_CLUT(16); break;
788  }
789 }
790 
791 static void update_clut_planar(LUT3DContext *lut3d, const AVFrame *frame)
792 {
793  const uint8_t *datag = frame->data[0];
794  const uint8_t *datab = frame->data[1];
795  const uint8_t *datar = frame->data[2];
796  const int glinesize = frame->linesize[0];
797  const int blinesize = frame->linesize[1];
798  const int rlinesize = frame->linesize[2];
799  const int w = lut3d->clut_width;
800  const int level = lut3d->lutsize;
801 
802 #define LOAD_CLUT_PLANAR(nbits, depth) do { \
803  int i, j, k, x = 0, y = 0; \
804  \
805  for (k = 0; k < level; k++) { \
806  for (j = 0; j < level; j++) { \
807  for (i = 0; i < level; i++) { \
808  const uint##nbits##_t *gsrc = (const uint##nbits##_t *) \
809  (datag + y*glinesize); \
810  const uint##nbits##_t *bsrc = (const uint##nbits##_t *) \
811  (datab + y*blinesize); \
812  const uint##nbits##_t *rsrc = (const uint##nbits##_t *) \
813  (datar + y*rlinesize); \
814  struct rgbvec *vec = &lut3d->lut[i][j][k]; \
815  vec->r = gsrc[x] / (float)((1<<(depth)) - 1); \
816  vec->g = bsrc[x] / (float)((1<<(depth)) - 1); \
817  vec->b = rsrc[x] / (float)((1<<(depth)) - 1); \
818  if (++x == w) { \
819  x = 0; \
820  y++; \
821  } \
822  } \
823  } \
824  } \
825 } while (0)
826 
827  switch (lut3d->clut_bits) {
828  case 8: LOAD_CLUT_PLANAR(8, 8); break;
829  case 9: LOAD_CLUT_PLANAR(16, 9); break;
830  case 10: LOAD_CLUT_PLANAR(16, 10); break;
831  case 12: LOAD_CLUT_PLANAR(16, 12); break;
832  case 14: LOAD_CLUT_PLANAR(16, 14); break;
833  case 16: LOAD_CLUT_PLANAR(16, 16); break;
834  }
835 }
836 
837 static int config_output(AVFilterLink *outlink)
838 {
839  AVFilterContext *ctx = outlink->src;
840  LUT3DContext *lut3d = ctx->priv;
841  int ret;
842 
843  ret = ff_framesync_init_dualinput(&lut3d->fs, ctx);
844  if (ret < 0)
845  return ret;
846  outlink->w = ctx->inputs[0]->w;
847  outlink->h = ctx->inputs[0]->h;
848  outlink->time_base = ctx->inputs[0]->time_base;
849  if ((ret = ff_framesync_configure(&lut3d->fs)) < 0)
850  return ret;
851  return 0;
852 }
853 
854 static int activate(AVFilterContext *ctx)
855 {
856  LUT3DContext *s = ctx->priv;
857  return ff_framesync_activate(&s->fs);
858 }
859 
860 static int config_clut(AVFilterLink *inlink)
861 {
862  int size, level, w, h;
863  AVFilterContext *ctx = inlink->dst;
864  LUT3DContext *lut3d = ctx->priv;
866 
867  av_assert0(desc);
868 
869  lut3d->clut_bits = desc->comp[0].depth;
870  lut3d->clut_planar = av_pix_fmt_count_planes(inlink->format) > 1;
871 
872  lut3d->clut_step = av_get_padded_bits_per_pixel(desc) >> 3;
873  ff_fill_rgba_map(lut3d->clut_rgba_map, inlink->format);
874 
875  if (inlink->w > inlink->h)
876  av_log(ctx, AV_LOG_INFO, "Padding on the right (%dpx) of the "
877  "Hald CLUT will be ignored\n", inlink->w - inlink->h);
878  else if (inlink->w < inlink->h)
879  av_log(ctx, AV_LOG_INFO, "Padding at the bottom (%dpx) of the "
880  "Hald CLUT will be ignored\n", inlink->h - inlink->w);
881  lut3d->clut_width = w = h = FFMIN(inlink->w, inlink->h);
882 
883  for (level = 1; level*level*level < w; level++);
884  size = level*level*level;
885  if (size != w) {
886  av_log(ctx, AV_LOG_WARNING, "The Hald CLUT width does not match the level\n");
887  return AVERROR_INVALIDDATA;
888  }
889  av_assert0(w == h && w == size);
890  level *= level;
891  if (level > MAX_LEVEL) {
892  const int max_clut_level = sqrt(MAX_LEVEL);
893  const int max_clut_size = max_clut_level*max_clut_level*max_clut_level;
894  av_log(ctx, AV_LOG_ERROR, "Too large Hald CLUT "
895  "(maximum level is %d, or %dx%d CLUT)\n",
896  max_clut_level, max_clut_size, max_clut_size);
897  return AVERROR(EINVAL);
898  }
899  lut3d->lutsize = level;
900 
901  return 0;
902 }
903 
904 static int update_apply_clut(FFFrameSync *fs)
905 {
906  AVFilterContext *ctx = fs->parent;
907  LUT3DContext *lut3d = ctx->priv;
908  AVFilterLink *inlink = ctx->inputs[0];
909  AVFrame *master, *second, *out;
910  int ret;
911 
912  ret = ff_framesync_dualinput_get(fs, &master, &second);
913  if (ret < 0)
914  return ret;
915  if (!second)
916  return ff_filter_frame(ctx->outputs[0], master);
917  if (lut3d->clut_planar)
918  update_clut_planar(ctx->priv, second);
919  else
920  update_clut_packed(ctx->priv, second);
921  out = apply_lut(inlink, master);
922  return ff_filter_frame(ctx->outputs[0], out);
923 }
924 
925 static av_cold int haldclut_init(AVFilterContext *ctx)
926 {
927  LUT3DContext *lut3d = ctx->priv;
928  lut3d->fs.on_event = update_apply_clut;
929  return 0;
930 }
931 
932 static av_cold void haldclut_uninit(AVFilterContext *ctx)
933 {
934  LUT3DContext *lut3d = ctx->priv;
935  ff_framesync_uninit(&lut3d->fs);
936 }
937 
938 static const AVOption haldclut_options[] = {
940 };
941 
942 FRAMESYNC_DEFINE_CLASS(haldclut, LUT3DContext, fs);
943 
944 static const AVFilterPad haldclut_inputs[] = {
945  {
946  .name = "main",
947  .type = AVMEDIA_TYPE_VIDEO,
948  .config_props = config_input,
949  },{
950  .name = "clut",
951  .type = AVMEDIA_TYPE_VIDEO,
952  .config_props = config_clut,
953  },
954  { NULL }
955 };
956 
957 static const AVFilterPad haldclut_outputs[] = {
958  {
959  .name = "default",
960  .type = AVMEDIA_TYPE_VIDEO,
961  .config_props = config_output,
962  },
963  { NULL }
964 };
965 
967  .name = "haldclut",
968  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a Hald CLUT."),
969  .priv_size = sizeof(LUT3DContext),
970  .preinit = haldclut_framesync_preinit,
971  .init = haldclut_init,
972  .uninit = haldclut_uninit,
974  .activate = activate,
975  .inputs = haldclut_inputs,
976  .outputs = haldclut_outputs,
977  .priv_class = &haldclut_class,
979 };
980 #endif
981 
982 #if CONFIG_LUT1D_FILTER
983 
984 enum interp_1d_mode {
985  INTERPOLATE_1D_NEAREST,
986  INTERPOLATE_1D_LINEAR,
987  INTERPOLATE_1D_CUBIC,
988  NB_INTERP_1D_MODE
989 };
990 
991 #define MAX_1D_LEVEL 65536
992 
993 typedef struct LUT1DContext {
994  const AVClass *class;
995  char *file;
996  int interpolation; ///<interp_1d_mode
997  uint8_t rgba_map[4];
998  int step;
999  float lut[3][MAX_1D_LEVEL];
1000  int lutsize;
1001  avfilter_action_func *interp;
1002 } LUT1DContext;
1003 
1004 #undef OFFSET
1005 #define OFFSET(x) offsetof(LUT1DContext, x)
1006 
1007 static void set_identity_matrix_1d(LUT1DContext *lut1d, int size)
1008 {
1009  const float c = 1. / (size - 1);
1010  int i;
1011 
1012  lut1d->lutsize = size;
1013  for (i = 0; i < size; i++) {
1014  lut1d->lut[0][i] = i * c;
1015  lut1d->lut[1][i] = i * c;
1016  lut1d->lut[2][i] = i * c;
1017  }
1018 }
1019 
1020 static int parse_cube_1d(AVFilterContext *ctx, FILE *f)
1021 {
1022  LUT1DContext *lut1d = ctx->priv;
1023  char line[MAX_LINE_SIZE];
1024  float min[3] = {0.0, 0.0, 0.0};
1025  float max[3] = {1.0, 1.0, 1.0};
1026 
1027  while (fgets(line, sizeof(line), f)) {
1028  if (!strncmp(line, "LUT_1D_SIZE ", 12)) {
1029  const int size = strtol(line + 12, NULL, 0);
1030  int i;
1031 
1032  if (size < 2 || size > MAX_1D_LEVEL) {
1033  av_log(ctx, AV_LOG_ERROR, "Too large or invalid 1D LUT size\n");
1034  return AVERROR(EINVAL);
1035  }
1036  lut1d->lutsize = size;
1037  for (i = 0; i < size; i++) {
1038  do {
1039 try_again:
1040  NEXT_LINE(0);
1041  if (!strncmp(line, "DOMAIN_", 7)) {
1042  float *vals = NULL;
1043  if (!strncmp(line + 7, "MIN ", 4)) vals = min;
1044  else if (!strncmp(line + 7, "MAX ", 4)) vals = max;
1045  if (!vals)
1046  return AVERROR_INVALIDDATA;
1047  sscanf(line + 11, "%f %f %f", vals, vals + 1, vals + 2);
1048  av_log(ctx, AV_LOG_DEBUG, "min: %f %f %f | max: %f %f %f\n",
1049  min[0], min[1], min[2], max[0], max[1], max[2]);
1050  goto try_again;
1051  } else if (!strncmp(line, "LUT_1D_INPUT_RANGE ", 19)) {
1052  sscanf(line + 19, "%f %f", min, max);
1053  min[1] = min[2] = min[0];
1054  max[1] = max[2] = max[0];
1055  goto try_again;
1056  } else if (!strncmp(line, "TITLE", 5)) {
1057  goto try_again;
1058  }
1059  } while (skip_line(line));
1060  if (sscanf(line, "%f %f %f", &lut1d->lut[0][i], &lut1d->lut[1][i], &lut1d->lut[2][i]) != 3)
1061  return AVERROR_INVALIDDATA;
1062  lut1d->lut[0][i] *= max[0] - min[0];
1063  lut1d->lut[1][i] *= max[1] - min[1];
1064  lut1d->lut[2][i] *= max[2] - min[2];
1065  }
1066  break;
1067  }
1068  }
1069  return 0;
1070 }
1071 
1072 static const AVOption lut1d_options[] = {
1073  { "file", "set 1D LUT file name", OFFSET(file), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
1074  { "interp", "select interpolation mode", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=INTERPOLATE_1D_LINEAR}, 0, NB_INTERP_1D_MODE-1, FLAGS, "interp_mode" },
1075  { "nearest", "use values from the nearest defined points", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_NEAREST}, INT_MIN, INT_MAX, FLAGS, "interp_mode" },
1076  { "linear", "use values from the linear interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_LINEAR}, INT_MIN, INT_MAX, FLAGS, "interp_mode" },
1077  { "cubic", "use values from the cubic interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_CUBIC}, INT_MIN, INT_MAX, FLAGS, "interp_mode" },
1078  { NULL }
1079 };
1080 
1081 AVFILTER_DEFINE_CLASS(lut1d);
1082 
1083 static inline float interp_1d_nearest(const LUT1DContext *lut1d,
1084  int idx, const float s)
1085 {
1086  return lut1d->lut[idx][NEAR(s)];
1087 }
1088 
1089 #define NEXT1D(x) (FFMIN((int)(x) + 1, lut1d->lutsize - 1))
1090 
1091 static inline float interp_1d_linear(const LUT1DContext *lut1d,
1092  int idx, const float s)
1093 {
1094  const int prev = PREV(s);
1095  const int next = NEXT1D(s);
1096  const float d = s - prev;
1097  const float p = lut1d->lut[idx][prev];
1098  const float n = lut1d->lut[idx][next];
1099 
1100  return lerpf(p, n, d);
1101 }
1102 
1103 static inline float interp_1d_cubic(const LUT1DContext *lut1d,
1104  int idx, const float s)
1105 {
1106  const int prev = PREV(s);
1107  const int next = NEXT1D(s);
1108  const float mu = s - prev;
1109  float a0, a1, a2, a3, mu2;
1110 
1111  float y0 = lut1d->lut[idx][FFMAX(prev - 1, 0)];
1112  float y1 = lut1d->lut[idx][prev];
1113  float y2 = lut1d->lut[idx][next];
1114  float y3 = lut1d->lut[idx][FFMIN(next + 1, lut1d->lutsize - 1)];
1115 
1116 
1117  mu2 = mu * mu;
1118  a0 = y3 - y2 - y0 + y1;
1119  a1 = y0 - y1 - a0;
1120  a2 = y2 - y0;
1121  a3 = y1;
1122 
1123  return a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3;
1124 }
1125 
1126 #define DEFINE_INTERP_FUNC_PLANAR_1D(name, nbits, depth) \
1127 static int interp_1d_##nbits##_##name##_p##depth(AVFilterContext *ctx, \
1128  void *arg, int jobnr, \
1129  int nb_jobs) \
1130 { \
1131  int x, y; \
1132  const LUT1DContext *lut1d = ctx->priv; \
1133  const ThreadData *td = arg; \
1134  const AVFrame *in = td->in; \
1135  const AVFrame *out = td->out; \
1136  const int direct = out == in; \
1137  const int slice_start = (in->height * jobnr ) / nb_jobs; \
1138  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
1139  uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
1140  uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
1141  uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
1142  uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
1143  const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
1144  const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
1145  const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
1146  const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
1147  const float factor = (1 << depth) - 1; \
1148  const float scale = (1. / factor) * (lut1d->lutsize - 1); \
1149  \
1150  for (y = slice_start; y < slice_end; y++) { \
1151  uint##nbits##_t *dstg = (uint##nbits##_t *)grow; \
1152  uint##nbits##_t *dstb = (uint##nbits##_t *)brow; \
1153  uint##nbits##_t *dstr = (uint##nbits##_t *)rrow; \
1154  uint##nbits##_t *dsta = (uint##nbits##_t *)arow; \
1155  const uint##nbits##_t *srcg = (const uint##nbits##_t *)srcgrow; \
1156  const uint##nbits##_t *srcb = (const uint##nbits##_t *)srcbrow; \
1157  const uint##nbits##_t *srcr = (const uint##nbits##_t *)srcrrow; \
1158  const uint##nbits##_t *srca = (const uint##nbits##_t *)srcarow; \
1159  for (x = 0; x < in->width; x++) { \
1160  float r = srcr[x] * scale; \
1161  float g = srcg[x] * scale; \
1162  float b = srcb[x] * scale; \
1163  r = interp_1d_##name(lut1d, 0, r); \
1164  g = interp_1d_##name(lut1d, 1, g); \
1165  b = interp_1d_##name(lut1d, 2, b); \
1166  dstr[x] = av_clip_uintp2(r * factor, depth); \
1167  dstg[x] = av_clip_uintp2(g * factor, depth); \
1168  dstb[x] = av_clip_uintp2(b * factor, depth); \
1169  if (!direct && in->linesize[3]) \
1170  dsta[x] = srca[x]; \
1171  } \
1172  grow += out->linesize[0]; \
1173  brow += out->linesize[1]; \
1174  rrow += out->linesize[2]; \
1175  arow += out->linesize[3]; \
1176  srcgrow += in->linesize[0]; \
1177  srcbrow += in->linesize[1]; \
1178  srcrrow += in->linesize[2]; \
1179  srcarow += in->linesize[3]; \
1180  } \
1181  return 0; \
1182 }
1183 
1184 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 8, 8)
1185 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 8, 8)
1186 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 8, 8)
1187 
1188 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 9)
1189 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 9)
1190 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 9)
1191 
1192 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 10)
1193 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 10)
1194 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 10)
1195 
1196 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 12)
1197 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 12)
1198 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 12)
1199 
1200 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 14)
1201 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 14)
1202 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 14)
1203 
1204 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 16)
1205 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 16)
1206 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 16)
1207 
1208 #define DEFINE_INTERP_FUNC_1D(name, nbits) \
1209 static int interp_1d_##nbits##_##name(AVFilterContext *ctx, void *arg, \
1210  int jobnr, int nb_jobs) \
1211 { \
1212  int x, y; \
1213  const LUT1DContext *lut1d = ctx->priv; \
1214  const ThreadData *td = arg; \
1215  const AVFrame *in = td->in; \
1216  const AVFrame *out = td->out; \
1217  const int direct = out == in; \
1218  const int step = lut1d->step; \
1219  const uint8_t r = lut1d->rgba_map[R]; \
1220  const uint8_t g = lut1d->rgba_map[G]; \
1221  const uint8_t b = lut1d->rgba_map[B]; \
1222  const uint8_t a = lut1d->rgba_map[A]; \
1223  const int slice_start = (in->height * jobnr ) / nb_jobs; \
1224  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
1225  uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \
1226  const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \
1227  const float factor = (1 << nbits) - 1; \
1228  const float scale = (1. / factor) * (lut1d->lutsize - 1); \
1229  \
1230  for (y = slice_start; y < slice_end; y++) { \
1231  uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \
1232  const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \
1233  for (x = 0; x < in->width * step; x += step) { \
1234  float rr = src[x + r] * scale; \
1235  float gg = src[x + g] * scale; \
1236  float bb = src[x + b] * scale; \
1237  rr = interp_1d_##name(lut1d, 0, rr); \
1238  gg = interp_1d_##name(lut1d, 1, gg); \
1239  bb = interp_1d_##name(lut1d, 2, bb); \
1240  dst[x + r] = av_clip_uint##nbits(rr * factor); \
1241  dst[x + g] = av_clip_uint##nbits(gg * factor); \
1242  dst[x + b] = av_clip_uint##nbits(bb * factor); \
1243  if (!direct && step == 4) \
1244  dst[x + a] = src[x + a]; \
1245  } \
1246  dstrow += out->linesize[0]; \
1247  srcrow += in ->linesize[0]; \
1248  } \
1249  return 0; \
1250 }
1251 
1252 DEFINE_INTERP_FUNC_1D(nearest, 8)
1253 DEFINE_INTERP_FUNC_1D(linear, 8)
1254 DEFINE_INTERP_FUNC_1D(cubic, 8)
1255 
1256 DEFINE_INTERP_FUNC_1D(nearest, 16)
1257 DEFINE_INTERP_FUNC_1D(linear, 16)
1258 DEFINE_INTERP_FUNC_1D(cubic, 16)
1259 
1260 static int config_input_1d(AVFilterLink *inlink)
1261 {
1262  int depth, is16bit = 0, planar = 0;
1263  LUT1DContext *lut1d = inlink->dst->priv;
1264  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
1265 
1266  depth = desc->comp[0].depth;
1267 
1268  switch (inlink->format) {
1269  case AV_PIX_FMT_RGB48:
1270  case AV_PIX_FMT_BGR48:
1271  case AV_PIX_FMT_RGBA64:
1272  case AV_PIX_FMT_BGRA64:
1273  is16bit = 1;
1274  break;
1275  case AV_PIX_FMT_GBRP9:
1276  case AV_PIX_FMT_GBRP10:
1277  case AV_PIX_FMT_GBRP12:
1278  case AV_PIX_FMT_GBRP14:
1279  case AV_PIX_FMT_GBRP16:
1280  case AV_PIX_FMT_GBRAP10:
1281  case AV_PIX_FMT_GBRAP12:
1282  case AV_PIX_FMT_GBRAP16:
1283  is16bit = 1;
1284  case AV_PIX_FMT_GBRP:
1285  case AV_PIX_FMT_GBRAP:
1286  planar = 1;
1287  break;
1288  }
1289 
1290  ff_fill_rgba_map(lut1d->rgba_map, inlink->format);
1291  lut1d->step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit);
1292 
1293 #define SET_FUNC_1D(name) do { \
1294  if (planar) { \
1295  switch (depth) { \
1296  case 8: lut1d->interp = interp_1d_8_##name##_p8; break; \
1297  case 9: lut1d->interp = interp_1d_16_##name##_p9; break; \
1298  case 10: lut1d->interp = interp_1d_16_##name##_p10; break; \
1299  case 12: lut1d->interp = interp_1d_16_##name##_p12; break; \
1300  case 14: lut1d->interp = interp_1d_16_##name##_p14; break; \
1301  case 16: lut1d->interp = interp_1d_16_##name##_p16; break; \
1302  } \
1303  } else if (is16bit) { lut1d->interp = interp_1d_16_##name; \
1304  } else { lut1d->interp = interp_1d_8_##name; } \
1305 } while (0)
1306 
1307  switch (lut1d->interpolation) {
1308  case INTERPOLATE_1D_NEAREST: SET_FUNC_1D(nearest); break;
1309  case INTERPOLATE_1D_LINEAR: SET_FUNC_1D(linear); break;
1310  case INTERPOLATE_1D_CUBIC: SET_FUNC_1D(cubic); break;
1311  default:
1312  av_assert0(0);
1313  }
1314 
1315  return 0;
1316 }
1317 
1318 static av_cold int lut1d_init(AVFilterContext *ctx)
1319 {
1320  int ret;
1321  FILE *f;
1322  const char *ext;
1323  LUT1DContext *lut1d = ctx->priv;
1324 
1325  if (!lut1d->file) {
1326  set_identity_matrix_1d(lut1d, 32);
1327  return 0;
1328  }
1329 
1330  f = fopen(lut1d->file, "r");
1331  if (!f) {
1332  ret = AVERROR(errno);
1333  av_log(ctx, AV_LOG_ERROR, "%s: %s\n", lut1d->file, av_err2str(ret));
1334  return ret;
1335  }
1336 
1337  ext = strrchr(lut1d->file, '.');
1338  if (!ext) {
1339  av_log(ctx, AV_LOG_ERROR, "Unable to guess the format from the extension\n");
1340  ret = AVERROR_INVALIDDATA;
1341  goto end;
1342  }
1343  ext++;
1344 
1345  if (!av_strcasecmp(ext, "cube") || !av_strcasecmp(ext, "1dlut")) {
1346  ret = parse_cube_1d(ctx, f);
1347  } else {
1348  av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext);
1349  ret = AVERROR(EINVAL);
1350  }
1351 
1352  if (!ret && !lut1d->lutsize) {
1353  av_log(ctx, AV_LOG_ERROR, "1D LUT is empty\n");
1354  ret = AVERROR_INVALIDDATA;
1355  }
1356 
1357 end:
1358  fclose(f);
1359  return ret;
1360 }
1361 
1362 static AVFrame *apply_1d_lut(AVFilterLink *inlink, AVFrame *in)
1363 {
1364  AVFilterContext *ctx = inlink->dst;
1365  LUT1DContext *lut1d = ctx->priv;
1366  AVFilterLink *outlink = inlink->dst->outputs[0];
1367  AVFrame *out;
1368  ThreadData td;
1369 
1370  if (av_frame_is_writable(in)) {
1371  out = in;
1372  } else {
1373  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
1374  if (!out) {
1375  av_frame_free(&in);
1376  return NULL;
1377  }
1378  av_frame_copy_props(out, in);
1379  }
1380 
1381  td.in = in;
1382  td.out = out;
1383  ctx->internal->execute(ctx, lut1d->interp, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
1384 
1385  if (out != in)
1386  av_frame_free(&in);
1387 
1388  return out;
1389 }
1390 
1391 static int filter_frame_1d(AVFilterLink *inlink, AVFrame *in)
1392 {
1393  AVFilterLink *outlink = inlink->dst->outputs[0];
1394  AVFrame *out = apply_1d_lut(inlink, in);
1395  if (!out)
1396  return AVERROR(ENOMEM);
1397  return ff_filter_frame(outlink, out);
1398 }
1399 
1400 static const AVFilterPad lut1d_inputs[] = {
1401  {
1402  .name = "default",
1403  .type = AVMEDIA_TYPE_VIDEO,
1404  .filter_frame = filter_frame_1d,
1405  .config_props = config_input_1d,
1406  },
1407  { NULL }
1408 };
1409 
1410 static const AVFilterPad lut1d_outputs[] = {
1411  {
1412  .name = "default",
1413  .type = AVMEDIA_TYPE_VIDEO,
1414  },
1415  { NULL }
1416 };
1417 
1419  .name = "lut1d",
1420  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a 1D LUT."),
1421  .priv_size = sizeof(LUT1DContext),
1422  .init = lut1d_init,
1424  .inputs = lut1d_inputs,
1425  .outputs = lut1d_outputs,
1426  .priv_class = &lut1d_class,
1428 };
1429 #endif
#define NULL
Definition: coverity.c:32
const char const char void * val
Definition: avisynth_c.h:771
#define FRAMESYNC_DEFINE_CLASS(name, context, field)
Definition: framesync.h:300
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
AVFrame * out
Definition: af_adeclick.c:485
#define COMMON_OPTIONS
Definition: vf_lut3d.c:85
static int config_input(AVFilterLink *inlink)
Definition: vf_lut3d.c:568
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2446
This structure describes decoded (raw) audio or video data.
Definition: frame.h:226
static int activate(AVFilterContext *ctx)
Definition: af_adelay.c:237
AVOption.
Definition: opt.h:246
static struct rgbvec interp_trilinear(const LUT3DContext *lut3d, const struct rgbvec *s)
Interpolate using the 8 vertices of a cube.
Definition: vf_lut3d.c:122
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:101
#define AV_PIX_FMT_GBRAP10
Definition: pixfmt.h:399
static int linear(InterplayACMContext *s, unsigned ind, unsigned col)
Definition: interplayacm.c:121
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2486
Main libavfilter public API header.
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
const char * g
Definition: vf_curves.c:115
const char * desc
Definition: nvenc.c:65
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:369
#define a0
Definition: regdef.h:46
planar GBR 4:4:4 24bpp
Definition: pixfmt.h:168
static int skip_line(const char *p)
Definition: vf_lut3d.c:330
const char * b
Definition: vf_curves.c:116
#define AV_PIX_FMT_GBRP10
Definition: pixfmt.h:395
static av_const int av_isspace(int c)
Locale-independent conversion of ASCII isspace.
Definition: avstring.h:222
#define AV_PIX_FMT_BGRA64
Definition: pixfmt.h:374
#define a1
Definition: regdef.h:47
static int parse_cube(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:379
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
Definition: framesync.c:117
packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined
Definition: pixfmt.h:239
const char * master
Definition: vf_curves.c:117
GLfloat v0
Definition: opengl_enc.c:107
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:99
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:283
#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:125
const char * name
Pad name.
Definition: internal.h:60
AVFilterContext * parent
Parent filter context.
Definition: framesync.h:152
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:346
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
#define MAX_LEVEL
Definition: vf_lut3d.c:58
AVFilter ff_vf_haldclut
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1080
#define a3
Definition: regdef.h:49
AVFrame * in
Definition: af_afftdn.c:1082
static float lerpf(float v0, float v1, float f)
Definition: vf_lut3d.c:92
AVComponentDescriptor comp[4]
Parameters that describe how pixels are packed.
Definition: pixdesc.h:117
AVFilter ff_vf_lut1d
uint8_t
#define av_cold
Definition: attributes.h:82
static av_cold int uninit(AVCodecContext *avctx)
Definition: crystalhd.c:279
#define fs(width, name, subs,...)
Definition: cbs_vp9.c:259
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:238
AVOptions.
int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent)
Initialize a frame sync structure for dualinput.
Definition: framesync.c:361
#define f(width, name)
Definition: cbs_vp9.c:255
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1)
Definition: framesync.c:379
static void set_identity_matrix(LUT3DContext *lut3d, int size)
Definition: vf_lut3d.c:526
#define AV_PIX_FMT_GBRP9
Definition: pixfmt.h:394
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
Definition: pixfmt.h:94
static AVFrame * frame
Misc file utilities.
#define NEAR(x)
Definition: vf_lut3d.c:105
#define OFFSET(x)
Definition: vf_lut3d.c:83
#define AV_PIX_FMT_BGR48
Definition: pixfmt.h:370
ptrdiff_t size
Definition: opengl_enc.c:101
#define av_log(a,...)
A filter pad used for either input or output.
Definition: internal.h:54
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:568
#define td
Definition: regdef.h:70
uint8_t rgba_map[4]
Definition: vf_lut3d.c:64
int( avfilter_action_func)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
A function pointer passed to the AVFilterGraph::execute callback to be executed multiple times...
Definition: avfilter.h:823
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition: framesync.c:293
interp_mode
Definition: vf_lut3d.c:45
#define DEFINE_INTERP_FUNC(name, nbits)
Definition: vf_lut3d.c:280
Frame sync structure.
Definition: framesync.h:146
#define AVERROR(e)
Definition: error.h:43
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:202
#define NEXT(x)
Definition: vf_lut3d.c:107
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
#define MAX_LINE_SIZE
Definition: vf_lut3d.c:328
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
const char * r
Definition: vf_curves.c:114
void * priv
private data for use by the filter
Definition: avfilter.h:353
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:2411
static struct rgbvec interp_nearest(const LUT3DContext *lut3d, const struct rgbvec *s)
Get the nearest defined point.
Definition: vf_lut3d.c:112
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:116
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
static int config_output(AVFilterLink *outlink)
Definition: af_aecho.c:232
Definition: graph2dot.c:48
#define AV_PIX_FMT_GBRAP12
Definition: pixfmt.h:400
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:365
simple assert() macros that are a bit more flexible than ISO C assert().
int ff_framesync_activate(FFFrameSync *fs)
Examine the frames in the filter's input and try to produce output.
Definition: framesync.c:344
#define FLAGS
Definition: vf_lut3d.c:84
#define FFMAX(a, b)
Definition: common.h:94
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition: pixfmt.h:92
#define AV_PIX_FMT_GBRAP16
Definition: pixfmt.h:401
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
#define SET_COLOR(id)
#define AV_PIX_FMT_GBRP16
Definition: pixfmt.h:398
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:802
#define FFMIN(a, b)
Definition: common.h:96
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition: avstring.c:213
uint8_t w
Definition: llviddspenc.c:38
static int interpolation(DeclickChannel *c, const double *src, int ar_order, double *acoefficients, int *index, int nb_errors, double *auxiliary, double *interpolated)
Definition: af_adeclick.c:348
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:119
AVFormatContext * ctx
Definition: movenc.c:48
#define a2
Definition: regdef.h:48
#define DEFINE_INTERP_FUNC_PLANAR(name, nbits, depth)
Definition: vf_lut3d.c:203
int lutsize
Definition: vf_lut3d.c:68
#define s(width, name)
Definition: cbs_vp9.c:257
int n
Definition: avisynth_c.h:684
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
static const AVFilterPad inputs[]
Definition: af_acontrast.c:193
#define AV_PIX_FMT_GBRP14
Definition: pixfmt.h:397
static AVFrame * apply_lut(AVFilterLink *inlink, AVFrame *in)
Definition: vf_lut3d.c:626
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
Definition: drawutils.c:35
#define PREV(x)
Definition: vf_lut3d.c:106
char * file
Definition: vf_lut3d.c:63
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
misc drawing utilities
int av_frame_is_writable(AVFrame *frame)
Check if the frame data is writable.
Definition: frame.c:594
Used for passing data between threads.
Definition: af_adeclick.c:484
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:257
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:81
float b
Definition: vf_lut3d.c:53
uint8_t pi<< 24) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_U8,(uint64_t)((*(constuint8_t *) pi-0x80U))<< 56) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8,(*(constuint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8,(*(constuint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16,(*(constint16_t *) pi >>8)+0x80) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S16,(uint64_t)(*(constint16_t *) pi)<< 48) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16,*(constint16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16,*(constint16_t *) pi *(1.0/(1<< 15))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32,(*(constint32_t *) pi >>24)+0x80) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S32,(uint64_t)(*(constint32_t *) pi)<< 32) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32,*(constint32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32,*(constint32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S64,(*(constint64_t *) pi >>56)+0x80) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S64,*(constint64_t *) pi *(1.0f/(INT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S64,*(constint64_t *) pi *(1.0/(INT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, av_clip_uint8(lrintf(*(constfloat *) pi *(1<< 7))+0x80)) CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, av_clip_int16(lrintf(*(constfloat *) pi *(1<< 15)))) CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(constfloat *) pi *(1U<< 31)))) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_FLT, llrintf(*(constfloat *) pi *(INT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, av_clip_uint8(lrint(*(constdouble *) pi *(1<< 7))+0x80)) CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, av_clip_int16(lrint(*(constdouble *) pi *(1<< 15)))) CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(constdouble *) pi *(1U<< 31)))) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_DBL, llrint(*(constdouble *) pi *(INT64_C(1)<< 63)))#defineFMT_PAIR_FUNC(out, in) staticconv_func_type *constfmt_pair_to_conv_functions[AV_SAMPLE_FMT_NB *AV_SAMPLE_FMT_NB]={FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64),};staticvoidcpy1(uint8_t **dst, constuint8_t **src, intlen){memcpy(*dst,*src, len);}staticvoidcpy2(uint8_t **dst, constuint8_t **src, intlen){memcpy(*dst,*src, 2 *len);}staticvoidcpy4(uint8_t **dst, constuint8_t **src, intlen){memcpy(*dst,*src, 4 *len);}staticvoidcpy8(uint8_t **dst, constuint8_t **src, intlen){memcpy(*dst,*src, 8 *len);}AudioConvert *swri_audio_convert_alloc(enumAVSampleFormatout_fmt, enumAVSampleFormatin_fmt, intchannels, constint *ch_map, intflags){AudioConvert *ctx;conv_func_type *f=fmt_pair_to_conv_functions[av_get_packed_sample_fmt(out_fmt)+AV_SAMPLE_FMT_NB *av_get_packed_sample_fmt(in_fmt)];if(!f) returnNULL;ctx=av_mallocz(sizeof(*ctx));if(!ctx) returnNULL;if(channels==1){in_fmt=av_get_planar_sample_fmt(in_fmt);out_fmt=av_get_planar_sample_fmt(out_fmt);}ctx->channels=channels;ctx->conv_f=f;ctx->ch_map=ch_map;if(in_fmt==AV_SAMPLE_FMT_U8||in_fmt==AV_SAMPLE_FMT_U8P) memset(ctx->silence, 0x80, sizeof(ctx->silence));if(out_fmt==in_fmt &&!ch_map){switch(av_get_bytes_per_sample(in_fmt)){case1:ctx->simd_f=cpy1;break;case2:ctx->simd_f=cpy2;break;case4:ctx->simd_f=cpy4;break;case8:ctx->simd_f=cpy8;break;}}if(HAVE_X86ASM &&1) swri_audio_convert_init_x86(ctx, out_fmt, in_fmt, channels);if(ARCH_ARM) swri_audio_convert_init_arm(ctx, out_fmt, in_fmt, channels);if(ARCH_AARCH64) swri_audio_convert_init_aarch64(ctx, out_fmt, in_fmt, channels);returnctx;}voidswri_audio_convert_free(AudioConvert **ctx){av_freep(ctx);}intswri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, intlen){intch;intoff=0;constintos=(out->planar?1:out->ch_count)*out->bps;unsignedmisaligned=0;av_assert0(ctx->channels==out->ch_count);if(ctx->in_simd_align_mask){intplanes=in->planar?in->ch_count:1;unsignedm=0;for(ch=0;ch< planes;ch++) m|=(intptr_t) in->ch[ch];misaligned|=m &ctx->in_simd_align_mask;}if(ctx->out_simd_align_mask){intplanes=out->planar?out->ch_count:1;unsignedm=0;for(ch=0;ch< planes;ch++) m|=(intptr_t) out->ch[ch];misaligned|=m &ctx->out_simd_align_mask;}if(ctx->simd_f &&!ctx->ch_map &&!misaligned){off=len &~15;av_assert1(off >=0);av_assert1(off<=len);av_assert2(ctx->channels==SWR_CH_MAX||!in->ch[ctx->channels]);if(off >0){if(out->planar==in->planar){intplanes=out->planar?out->ch_count:1;for(ch=0;ch< planes;ch++){ctx->simd_f(out-> ch const uint8_t **in ch off *out planar
Definition: audioconvert.c:56
static struct rgbvec lerp(const struct rgbvec *v0, const struct rgbvec *v1, float f)
Definition: vf_lut3d.c:97
int interpolation
interp_mode
Definition: vf_lut3d.c:62
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(constuint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(constuint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(constint16_t *) pi >>8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t,*(constint16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t,*(constint16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(constint32_t *) pi >>24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t,*(constint32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t,*(constint32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(constfloat *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(constfloat *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(constfloat *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(constdouble *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(constdouble *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(constdouble *) pi *(1U<< 31))))#defineSET_CONV_FUNC_GROUP(ofmt, ifmt) staticvoidset_generic_function(AudioConvert *ac){}voidff_audio_convert_free(AudioConvert **ac){if(!*ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);}AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enumAVSampleFormatout_fmt, enumAVSampleFormatin_fmt, intchannels, intsample_rate, intapply_map){AudioConvert *ac;intin_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) returnNULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method!=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt)>2){ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc){av_free(ac);returnNULL;}returnac;}in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar){ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar?ac->channels:1;}elseif(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;elseac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);returnac;}intff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in){intuse_generic=1;intlen=in->nb_samples;intp;if(ac->dc){av_log(ac->avr, AV_LOG_TRACE,"%dsamples-audio_convert:%sto%s(dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));returnff_convert_dither(ac-> in
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:144
AVFilter ff_vf_lut3d
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:240
const char * name
Filter name.
Definition: avfilter.h:148
#define AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
Same as AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, except that the filter will have its filter_frame() c...
Definition: avfilter.h:133
static struct rgbvec interp_tetrahedral(const LUT3DContext *lut3d, const struct rgbvec *s)
Tetrahedral interpolation.
Definition: vf_lut3d.c:150
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:350
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:266
#define AV_PIX_FMT_GBRP12
Definition: pixfmt.h:396
#define flags(name, subs,...)
Definition: cbs_av1.c:596
AVFilterInternal * internal
An opaque struct for libavfilter internal use.
Definition: avfilter.h:378
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:240
uint8_t level
Definition: svq3.c:207
planar GBRA 4:4:4:4 32bpp
Definition: pixfmt.h:215
static double c[64]
#define NEXT_LINE(loop_cond)
Definition: vf_lut3d.c:337
static int parse_m3d(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:463
static int parse_3dl(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:434
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_lut3d.c:655
avfilter_execute_func * execute
Definition: internal.h:155
static int parse_dat(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:346
float r
Definition: vf_lut3d.c:53
#define AVFILTER_DEFINE_CLASS(fname)
Definition: internal.h:334
A list of supported formats for one end of a filter link.
Definition: formats.h:64
An instance of a filter.
Definition: avfilter.h:338
FILE * out
Definition: movenc.c:54
static int query_formats(AVFilterContext *ctx)
Definition: vf_lut3d.c:544
float g
Definition: vf_lut3d.c:53
internal API functions
int depth
Number of bits in the component.
Definition: pixdesc.h:58
#define SET_FUNC(name)
packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined
Definition: pixfmt.h:237
float min
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:654
avfilter_action_func * interp
Definition: vf_lut3d.c:66
struct rgbvec lut[MAX_LEVEL][MAX_LEVEL][MAX_LEVEL]
Definition: vf_lut3d.c:67