FFmpeg
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 "float.h"
28 
29 #include "libavutil/opt.h"
30 #include "libavutil/file.h"
31 #include "libavutil/intreadwrite.h"
32 #include "libavutil/intfloat.h"
33 #include "libavutil/avassert.h"
34 #include "libavutil/pixdesc.h"
35 #include "libavutil/avstring.h"
36 #include "avfilter.h"
37 #include "drawutils.h"
38 #include "formats.h"
39 #include "framesync.h"
40 #include "internal.h"
41 #include "video.h"
42 
43 #define R 0
44 #define G 1
45 #define B 2
46 #define A 3
47 
55 };
56 
57 struct rgbvec {
58  float r, g, b;
59 };
60 
61 /* 3D LUT don't often go up to level 32, but it is common to have a Hald CLUT
62  * of 512x512 (64x64x64) */
63 #define MAX_LEVEL 256
64 #define PRELUT_SIZE 65536
65 
66 typedef struct Lut3DPreLut {
67  int size;
68  float min[3];
69  float max[3];
70  float scale[3];
71  float* lut[3];
72 } Lut3DPreLut;
73 
74 typedef struct LUT3DContext {
75  const AVClass *class;
76  int interpolation; ///<interp_mode
77  char *file;
78  uint8_t rgba_map[4];
79  int step;
81  struct rgbvec scale;
82  struct rgbvec *lut;
83  int lutsize;
84  int lutsize2;
86 #if CONFIG_HALDCLUT_FILTER
87  uint8_t clut_rgba_map[4];
88  int clut_step;
89  int clut_bits;
90  int clut_planar;
91  int clut_float;
92  int clut_width;
94 #endif
95 } LUT3DContext;
96 
97 typedef struct ThreadData {
98  AVFrame *in, *out;
99 } ThreadData;
100 
101 #define OFFSET(x) offsetof(LUT3DContext, x)
102 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
103 #define TFLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
104 #define COMMON_OPTIONS \
105  { "interp", "select interpolation mode", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=INTERPOLATE_TETRAHEDRAL}, 0, NB_INTERP_MODE-1, TFLAGS, "interp_mode" }, \
106  { "nearest", "use values from the nearest defined points", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_NEAREST}, 0, 0, TFLAGS, "interp_mode" }, \
107  { "trilinear", "interpolate values using the 8 points defining a cube", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_TRILINEAR}, 0, 0, TFLAGS, "interp_mode" }, \
108  { "tetrahedral", "interpolate values using a tetrahedron", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_TETRAHEDRAL}, 0, 0, TFLAGS, "interp_mode" }, \
109  { "pyramid", "interpolate values using a pyramid", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_PYRAMID}, 0, 0, TFLAGS, "interp_mode" }, \
110  { "prism", "interpolate values using a prism", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_PRISM}, 0, 0, TFLAGS, "interp_mode" }, \
111  { NULL }
112 
113 #define EXPONENT_MASK 0x7F800000
114 #define MANTISSA_MASK 0x007FFFFF
115 #define SIGN_MASK 0x80000000
116 
117 static inline float sanitizef(float f)
118 {
119  union av_intfloat32 t;
120  t.f = f;
121 
122  if ((t.i & EXPONENT_MASK) == EXPONENT_MASK) {
123  if ((t.i & MANTISSA_MASK) != 0) {
124  // NAN
125  return 0.0f;
126  } else if (t.i & SIGN_MASK) {
127  // -INF
128  return -FLT_MAX;
129  } else {
130  // +INF
131  return FLT_MAX;
132  }
133  }
134  return f;
135 }
136 
137 static inline float lerpf(float v0, float v1, float f)
138 {
139  return v0 + (v1 - v0) * f;
140 }
141 
142 static inline struct rgbvec lerp(const struct rgbvec *v0, const struct rgbvec *v1, float f)
143 {
144  struct rgbvec v = {
145  lerpf(v0->r, v1->r, f), lerpf(v0->g, v1->g, f), lerpf(v0->b, v1->b, f)
146  };
147  return v;
148 }
149 
150 #define NEAR(x) ((int)((x) + .5))
151 #define PREV(x) ((int)(x))
152 #define NEXT(x) (FFMIN((int)(x) + 1, lut3d->lutsize - 1))
153 
154 /**
155  * Get the nearest defined point
156  */
157 static inline struct rgbvec interp_nearest(const LUT3DContext *lut3d,
158  const struct rgbvec *s)
159 {
160  return lut3d->lut[NEAR(s->r) * lut3d->lutsize2 + NEAR(s->g) * lut3d->lutsize + NEAR(s->b)];
161 }
162 
163 /**
164  * Interpolate using the 8 vertices of a cube
165  * @see https://en.wikipedia.org/wiki/Trilinear_interpolation
166  */
167 static inline struct rgbvec interp_trilinear(const LUT3DContext *lut3d,
168  const struct rgbvec *s)
169 {
170  const int lutsize2 = lut3d->lutsize2;
171  const int lutsize = lut3d->lutsize;
172  const int prev[] = {PREV(s->r), PREV(s->g), PREV(s->b)};
173  const int next[] = {NEXT(s->r), NEXT(s->g), NEXT(s->b)};
174  const struct rgbvec d = {s->r - prev[0], s->g - prev[1], s->b - prev[2]};
175  const struct rgbvec c000 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + prev[2]];
176  const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
177  const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
178  const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
179  const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
180  const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
181  const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
182  const struct rgbvec c111 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + next[2]];
183  const struct rgbvec c00 = lerp(&c000, &c100, d.r);
184  const struct rgbvec c10 = lerp(&c010, &c110, d.r);
185  const struct rgbvec c01 = lerp(&c001, &c101, d.r);
186  const struct rgbvec c11 = lerp(&c011, &c111, d.r);
187  const struct rgbvec c0 = lerp(&c00, &c10, d.g);
188  const struct rgbvec c1 = lerp(&c01, &c11, d.g);
189  const struct rgbvec c = lerp(&c0, &c1, d.b);
190  return c;
191 }
192 
193 static inline struct rgbvec interp_pyramid(const LUT3DContext *lut3d,
194  const struct rgbvec *s)
195 {
196  const int lutsize2 = lut3d->lutsize2;
197  const int lutsize = lut3d->lutsize;
198  const int prev[] = {PREV(s->r), PREV(s->g), PREV(s->b)};
199  const int next[] = {NEXT(s->r), NEXT(s->g), NEXT(s->b)};
200  const struct rgbvec d = {s->r - prev[0], s->g - prev[1], s->b - prev[2]};
201  const struct rgbvec c000 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + prev[2]];
202  const struct rgbvec c111 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + next[2]];
203  struct rgbvec c;
204 
205  if (d.g > d.r && d.b > d.r) {
206  const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
207  const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
208  const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
209 
210  c.r = c000.r + (c111.r - c011.r) * d.r + (c010.r - c000.r) * d.g + (c001.r - c000.r) * d.b +
211  (c011.r - c001.r - c010.r + c000.r) * d.g * d.b;
212  c.g = c000.g + (c111.g - c011.g) * d.r + (c010.g - c000.g) * d.g + (c001.g - c000.g) * d.b +
213  (c011.g - c001.g - c010.g + c000.g) * d.g * d.b;
214  c.b = c000.b + (c111.b - c011.b) * d.r + (c010.b - c000.b) * d.g + (c001.b - c000.b) * d.b +
215  (c011.b - c001.b - c010.b + c000.b) * d.g * d.b;
216  } else if (d.r > d.g && d.b > d.g) {
217  const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
218  const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
219  const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
220 
221  c.r = c000.r + (c100.r - c000.r) * d.r + (c111.r - c101.r) * d.g + (c001.r - c000.r) * d.b +
222  (c101.r - c001.r - c100.r + c000.r) * d.r * d.b;
223  c.g = c000.g + (c100.g - c000.g) * d.r + (c111.g - c101.g) * d.g + (c001.g - c000.g) * d.b +
224  (c101.g - c001.g - c100.g + c000.g) * d.r * d.b;
225  c.b = c000.b + (c100.b - c000.b) * d.r + (c111.b - c101.b) * d.g + (c001.b - c000.b) * d.b +
226  (c101.b - c001.b - c100.b + c000.b) * d.r * d.b;
227  } else {
228  const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
229  const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
230  const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
231 
232  c.r = c000.r + (c100.r - c000.r) * d.r + (c010.r - c000.r) * d.g + (c111.r - c110.r) * d.b +
233  (c110.r - c100.r - c010.r + c000.r) * d.r * d.g;
234  c.g = c000.g + (c100.g - c000.g) * d.r + (c010.g - c000.g) * d.g + (c111.g - c110.g) * d.b +
235  (c110.g - c100.g - c010.g + c000.g) * d.r * d.g;
236  c.b = c000.b + (c100.b - c000.b) * d.r + (c010.b - c000.b) * d.g + (c111.b - c110.b) * d.b +
237  (c110.b - c100.b - c010.b + c000.b) * d.r * d.g;
238  }
239 
240  return c;
241 }
242 
243 static inline struct rgbvec interp_prism(const LUT3DContext *lut3d,
244  const struct rgbvec *s)
245 {
246  const int lutsize2 = lut3d->lutsize2;
247  const int lutsize = lut3d->lutsize;
248  const int prev[] = {PREV(s->r), PREV(s->g), PREV(s->b)};
249  const int next[] = {NEXT(s->r), NEXT(s->g), NEXT(s->b)};
250  const struct rgbvec d = {s->r - prev[0], s->g - prev[1], s->b - prev[2]};
251  const struct rgbvec c000 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + prev[2]];
252  const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
253  const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
254  const struct rgbvec c111 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + next[2]];
255  struct rgbvec c;
256 
257  if (d.b > d.r) {
258  const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
259  const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
260 
261  c.r = c000.r + (c001.r - c000.r) * d.b + (c101.r - c001.r) * d.r + (c010.r - c000.r) * d.g +
262  (c000.r - c010.r - c001.r + c011.r) * d.b * d.g +
263  (c001.r - c011.r - c101.r + c111.r) * d.r * d.g;
264  c.g = c000.g + (c001.g - c000.g) * d.b + (c101.g - c001.g) * d.r + (c010.g - c000.g) * d.g +
265  (c000.g - c010.g - c001.g + c011.g) * d.b * d.g +
266  (c001.g - c011.g - c101.g + c111.g) * d.r * d.g;
267  c.b = c000.b + (c001.b - c000.b) * d.b + (c101.b - c001.b) * d.r + (c010.b - c000.b) * d.g +
268  (c000.b - c010.b - c001.b + c011.b) * d.b * d.g +
269  (c001.b - c011.b - c101.b + c111.b) * d.r * d.g;
270  } else {
271  const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
272  const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
273 
274  c.r = c000.r + (c101.r - c100.r) * d.b + (c100.r - c000.r) * d.r + (c010.r - c000.r) * d.g +
275  (c100.r - c110.r - c101.r + c111.r) * d.b * d.g +
276  (c000.r - c010.r - c100.r + c110.r) * d.r * d.g;
277  c.g = c000.g + (c101.g - c100.g) * d.b + (c100.g - c000.g) * d.r + (c010.g - c000.g) * d.g +
278  (c100.g - c110.g - c101.g + c111.g) * d.b * d.g +
279  (c000.g - c010.g - c100.g + c110.g) * d.r * d.g;
280  c.b = c000.b + (c101.b - c100.b) * d.b + (c100.b - c000.b) * d.r + (c010.b - c000.b) * d.g +
281  (c100.b - c110.b - c101.b + c111.b) * d.b * d.g +
282  (c000.b - c010.b - c100.b + c110.b) * d.r * d.g;
283  }
284 
285  return c;
286 }
287 
288 /**
289  * Tetrahedral interpolation. Based on code found in Truelight Software Library paper.
290  * @see http://www.filmlight.ltd.uk/pdf/whitepapers/FL-TL-TN-0057-SoftwareLib.pdf
291  */
292 static inline struct rgbvec interp_tetrahedral(const LUT3DContext *lut3d,
293  const struct rgbvec *s)
294 {
295  const int lutsize2 = lut3d->lutsize2;
296  const int lutsize = lut3d->lutsize;
297  const int prev[] = {PREV(s->r), PREV(s->g), PREV(s->b)};
298  const int next[] = {NEXT(s->r), NEXT(s->g), NEXT(s->b)};
299  const struct rgbvec d = {s->r - prev[0], s->g - prev[1], s->b - prev[2]};
300  const struct rgbvec c000 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + prev[2]];
301  const struct rgbvec c111 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + next[2]];
302  struct rgbvec c;
303  if (d.r > d.g) {
304  if (d.g > d.b) {
305  const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
306  const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
307  c.r = (1-d.r) * c000.r + (d.r-d.g) * c100.r + (d.g-d.b) * c110.r + (d.b) * c111.r;
308  c.g = (1-d.r) * c000.g + (d.r-d.g) * c100.g + (d.g-d.b) * c110.g + (d.b) * c111.g;
309  c.b = (1-d.r) * c000.b + (d.r-d.g) * c100.b + (d.g-d.b) * c110.b + (d.b) * c111.b;
310  } else if (d.r > d.b) {
311  const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
312  const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
313  c.r = (1-d.r) * c000.r + (d.r-d.b) * c100.r + (d.b-d.g) * c101.r + (d.g) * c111.r;
314  c.g = (1-d.r) * c000.g + (d.r-d.b) * c100.g + (d.b-d.g) * c101.g + (d.g) * c111.g;
315  c.b = (1-d.r) * c000.b + (d.r-d.b) * c100.b + (d.b-d.g) * c101.b + (d.g) * c111.b;
316  } else {
317  const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
318  const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
319  c.r = (1-d.b) * c000.r + (d.b-d.r) * c001.r + (d.r-d.g) * c101.r + (d.g) * c111.r;
320  c.g = (1-d.b) * c000.g + (d.b-d.r) * c001.g + (d.r-d.g) * c101.g + (d.g) * c111.g;
321  c.b = (1-d.b) * c000.b + (d.b-d.r) * c001.b + (d.r-d.g) * c101.b + (d.g) * c111.b;
322  }
323  } else {
324  if (d.b > d.g) {
325  const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
326  const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
327  c.r = (1-d.b) * c000.r + (d.b-d.g) * c001.r + (d.g-d.r) * c011.r + (d.r) * c111.r;
328  c.g = (1-d.b) * c000.g + (d.b-d.g) * c001.g + (d.g-d.r) * c011.g + (d.r) * c111.g;
329  c.b = (1-d.b) * c000.b + (d.b-d.g) * c001.b + (d.g-d.r) * c011.b + (d.r) * c111.b;
330  } else if (d.b > d.r) {
331  const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
332  const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
333  c.r = (1-d.g) * c000.r + (d.g-d.b) * c010.r + (d.b-d.r) * c011.r + (d.r) * c111.r;
334  c.g = (1-d.g) * c000.g + (d.g-d.b) * c010.g + (d.b-d.r) * c011.g + (d.r) * c111.g;
335  c.b = (1-d.g) * c000.b + (d.g-d.b) * c010.b + (d.b-d.r) * c011.b + (d.r) * c111.b;
336  } else {
337  const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
338  const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
339  c.r = (1-d.g) * c000.r + (d.g-d.r) * c010.r + (d.r-d.b) * c110.r + (d.b) * c111.r;
340  c.g = (1-d.g) * c000.g + (d.g-d.r) * c010.g + (d.r-d.b) * c110.g + (d.b) * c111.g;
341  c.b = (1-d.g) * c000.b + (d.g-d.r) * c010.b + (d.r-d.b) * c110.b + (d.b) * c111.b;
342  }
343  }
344  return c;
345 }
346 
347 static inline float prelut_interp_1d_linear(const Lut3DPreLut *prelut,
348  int idx, const float s)
349 {
350  const int lut_max = prelut->size - 1;
351  const float scaled = (s - prelut->min[idx]) * prelut->scale[idx];
352  const float x = av_clipf(scaled, 0.0f, lut_max);
353  const int prev = PREV(x);
354  const int next = FFMIN((int)(x) + 1, lut_max);
355  const float p = prelut->lut[idx][prev];
356  const float n = prelut->lut[idx][next];
357  const float d = x - (float)prev;
358  return lerpf(p, n, d);
359 }
360 
361 static inline struct rgbvec apply_prelut(const Lut3DPreLut *prelut,
362  const struct rgbvec *s)
363 {
364  struct rgbvec c;
365 
366  if (prelut->size <= 0)
367  return *s;
368 
369  c.r = prelut_interp_1d_linear(prelut, 0, s->r);
370  c.g = prelut_interp_1d_linear(prelut, 1, s->g);
371  c.b = prelut_interp_1d_linear(prelut, 2, s->b);
372  return c;
373 }
374 
375 #define DEFINE_INTERP_FUNC_PLANAR(name, nbits, depth) \
376 static int interp_##nbits##_##name##_p##depth(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
377 { \
378  int x, y; \
379  const LUT3DContext *lut3d = ctx->priv; \
380  const Lut3DPreLut *prelut = &lut3d->prelut; \
381  const ThreadData *td = arg; \
382  const AVFrame *in = td->in; \
383  const AVFrame *out = td->out; \
384  const int direct = out == in; \
385  const int slice_start = (in->height * jobnr ) / nb_jobs; \
386  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
387  uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
388  uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
389  uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
390  uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
391  const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
392  const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
393  const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
394  const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
395  const float lut_max = lut3d->lutsize - 1; \
396  const float scale_f = 1.0f / ((1<<depth) - 1); \
397  const float scale_r = lut3d->scale.r * lut_max; \
398  const float scale_g = lut3d->scale.g * lut_max; \
399  const float scale_b = lut3d->scale.b * lut_max; \
400  \
401  for (y = slice_start; y < slice_end; y++) { \
402  uint##nbits##_t *dstg = (uint##nbits##_t *)grow; \
403  uint##nbits##_t *dstb = (uint##nbits##_t *)brow; \
404  uint##nbits##_t *dstr = (uint##nbits##_t *)rrow; \
405  uint##nbits##_t *dsta = (uint##nbits##_t *)arow; \
406  const uint##nbits##_t *srcg = (const uint##nbits##_t *)srcgrow; \
407  const uint##nbits##_t *srcb = (const uint##nbits##_t *)srcbrow; \
408  const uint##nbits##_t *srcr = (const uint##nbits##_t *)srcrrow; \
409  const uint##nbits##_t *srca = (const uint##nbits##_t *)srcarow; \
410  for (x = 0; x < in->width; x++) { \
411  const struct rgbvec rgb = {srcr[x] * scale_f, \
412  srcg[x] * scale_f, \
413  srcb[x] * scale_f}; \
414  const struct rgbvec prelut_rgb = apply_prelut(prelut, &rgb); \
415  const struct rgbvec scaled_rgb = {av_clipf(prelut_rgb.r * scale_r, 0, lut_max), \
416  av_clipf(prelut_rgb.g * scale_g, 0, lut_max), \
417  av_clipf(prelut_rgb.b * scale_b, 0, lut_max)}; \
418  struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \
419  dstr[x] = av_clip_uintp2(vec.r * (float)((1<<depth) - 1), depth); \
420  dstg[x] = av_clip_uintp2(vec.g * (float)((1<<depth) - 1), depth); \
421  dstb[x] = av_clip_uintp2(vec.b * (float)((1<<depth) - 1), depth); \
422  if (!direct && in->linesize[3]) \
423  dsta[x] = srca[x]; \
424  } \
425  grow += out->linesize[0]; \
426  brow += out->linesize[1]; \
427  rrow += out->linesize[2]; \
428  arow += out->linesize[3]; \
429  srcgrow += in->linesize[0]; \
430  srcbrow += in->linesize[1]; \
431  srcrrow += in->linesize[2]; \
432  srcarow += in->linesize[3]; \
433  } \
434  return 0; \
435 }
436 
437 DEFINE_INTERP_FUNC_PLANAR(nearest, 8, 8)
438 DEFINE_INTERP_FUNC_PLANAR(trilinear, 8, 8)
439 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 8, 8)
440 DEFINE_INTERP_FUNC_PLANAR(pyramid, 8, 8)
441 DEFINE_INTERP_FUNC_PLANAR(prism, 8, 8)
442 
443 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 9)
444 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 9)
445 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 9)
446 DEFINE_INTERP_FUNC_PLANAR(pyramid, 16, 9)
447 DEFINE_INTERP_FUNC_PLANAR(prism, 16, 9)
448 
449 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 10)
450 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 10)
451 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 10)
452 DEFINE_INTERP_FUNC_PLANAR(pyramid, 16, 10)
453 DEFINE_INTERP_FUNC_PLANAR(prism, 16, 10)
454 
455 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 12)
456 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 12)
457 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 12)
458 DEFINE_INTERP_FUNC_PLANAR(pyramid, 16, 12)
459 DEFINE_INTERP_FUNC_PLANAR(prism, 16, 12)
460 
461 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 14)
462 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 14)
463 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 14)
464 DEFINE_INTERP_FUNC_PLANAR(pyramid, 16, 14)
465 DEFINE_INTERP_FUNC_PLANAR(prism, 16, 14)
466 
467 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 16)
468 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 16)
469 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 16)
470 DEFINE_INTERP_FUNC_PLANAR(pyramid, 16, 16)
471 DEFINE_INTERP_FUNC_PLANAR(prism, 16, 16)
472 
473 #define DEFINE_INTERP_FUNC_PLANAR_FLOAT(name, depth) \
474 static int interp_##name##_pf##depth(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
475 { \
476  int x, y; \
477  const LUT3DContext *lut3d = ctx->priv; \
478  const Lut3DPreLut *prelut = &lut3d->prelut; \
479  const ThreadData *td = arg; \
480  const AVFrame *in = td->in; \
481  const AVFrame *out = td->out; \
482  const int direct = out == in; \
483  const int slice_start = (in->height * jobnr ) / nb_jobs; \
484  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
485  uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
486  uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
487  uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
488  uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
489  const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
490  const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
491  const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
492  const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
493  const float lut_max = lut3d->lutsize - 1; \
494  const float scale_r = lut3d->scale.r * lut_max; \
495  const float scale_g = lut3d->scale.g * lut_max; \
496  const float scale_b = lut3d->scale.b * lut_max; \
497  \
498  for (y = slice_start; y < slice_end; y++) { \
499  float *dstg = (float *)grow; \
500  float *dstb = (float *)brow; \
501  float *dstr = (float *)rrow; \
502  float *dsta = (float *)arow; \
503  const float *srcg = (const float *)srcgrow; \
504  const float *srcb = (const float *)srcbrow; \
505  const float *srcr = (const float *)srcrrow; \
506  const float *srca = (const float *)srcarow; \
507  for (x = 0; x < in->width; x++) { \
508  const struct rgbvec rgb = {sanitizef(srcr[x]), \
509  sanitizef(srcg[x]), \
510  sanitizef(srcb[x])}; \
511  const struct rgbvec prelut_rgb = apply_prelut(prelut, &rgb); \
512  const struct rgbvec scaled_rgb = {av_clipf(prelut_rgb.r * scale_r, 0, lut_max), \
513  av_clipf(prelut_rgb.g * scale_g, 0, lut_max), \
514  av_clipf(prelut_rgb.b * scale_b, 0, lut_max)}; \
515  struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \
516  dstr[x] = vec.r; \
517  dstg[x] = vec.g; \
518  dstb[x] = vec.b; \
519  if (!direct && in->linesize[3]) \
520  dsta[x] = srca[x]; \
521  } \
522  grow += out->linesize[0]; \
523  brow += out->linesize[1]; \
524  rrow += out->linesize[2]; \
525  arow += out->linesize[3]; \
526  srcgrow += in->linesize[0]; \
527  srcbrow += in->linesize[1]; \
528  srcrrow += in->linesize[2]; \
529  srcarow += in->linesize[3]; \
530  } \
531  return 0; \
532 }
533 
535 DEFINE_INTERP_FUNC_PLANAR_FLOAT(trilinear, 32)
536 DEFINE_INTERP_FUNC_PLANAR_FLOAT(tetrahedral, 32)
539 
540 #define DEFINE_INTERP_FUNC(name, nbits) \
541 static int interp_##nbits##_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
542 { \
543  int x, y; \
544  const LUT3DContext *lut3d = ctx->priv; \
545  const Lut3DPreLut *prelut = &lut3d->prelut; \
546  const ThreadData *td = arg; \
547  const AVFrame *in = td->in; \
548  const AVFrame *out = td->out; \
549  const int direct = out == in; \
550  const int step = lut3d->step; \
551  const uint8_t r = lut3d->rgba_map[R]; \
552  const uint8_t g = lut3d->rgba_map[G]; \
553  const uint8_t b = lut3d->rgba_map[B]; \
554  const uint8_t a = lut3d->rgba_map[A]; \
555  const int slice_start = (in->height * jobnr ) / nb_jobs; \
556  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
557  uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \
558  const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \
559  const float lut_max = lut3d->lutsize - 1; \
560  const float scale_f = 1.0f / ((1<<nbits) - 1); \
561  const float scale_r = lut3d->scale.r * lut_max; \
562  const float scale_g = lut3d->scale.g * lut_max; \
563  const float scale_b = lut3d->scale.b * lut_max; \
564  \
565  for (y = slice_start; y < slice_end; y++) { \
566  uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \
567  const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \
568  for (x = 0; x < in->width * step; x += step) { \
569  const struct rgbvec rgb = {src[x + r] * scale_f, \
570  src[x + g] * scale_f, \
571  src[x + b] * scale_f}; \
572  const struct rgbvec prelut_rgb = apply_prelut(prelut, &rgb); \
573  const struct rgbvec scaled_rgb = {av_clipf(prelut_rgb.r * scale_r, 0, lut_max), \
574  av_clipf(prelut_rgb.g * scale_g, 0, lut_max), \
575  av_clipf(prelut_rgb.b * scale_b, 0, lut_max)}; \
576  struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \
577  dst[x + r] = av_clip_uint##nbits(vec.r * (float)((1<<nbits) - 1)); \
578  dst[x + g] = av_clip_uint##nbits(vec.g * (float)((1<<nbits) - 1)); \
579  dst[x + b] = av_clip_uint##nbits(vec.b * (float)((1<<nbits) - 1)); \
580  if (!direct && step == 4) \
581  dst[x + a] = src[x + a]; \
582  } \
583  dstrow += out->linesize[0]; \
584  srcrow += in ->linesize[0]; \
585  } \
586  return 0; \
587 }
588 
589 DEFINE_INTERP_FUNC(nearest, 8)
590 DEFINE_INTERP_FUNC(trilinear, 8)
591 DEFINE_INTERP_FUNC(tetrahedral, 8)
592 DEFINE_INTERP_FUNC(pyramid, 8)
593 DEFINE_INTERP_FUNC(prism, 8)
594 
595 DEFINE_INTERP_FUNC(nearest, 16)
596 DEFINE_INTERP_FUNC(trilinear, 16)
597 DEFINE_INTERP_FUNC(tetrahedral, 16)
598 DEFINE_INTERP_FUNC(pyramid, 16)
599 DEFINE_INTERP_FUNC(prism, 16)
600 
601 #define MAX_LINE_SIZE 512
602 
603 static int skip_line(const char *p)
604 {
605  while (*p && av_isspace(*p))
606  p++;
607  return !*p || *p == '#';
608 }
609 
610 static char* fget_next_word(char* dst, int max, FILE* f)
611 {
612  int c;
613  char *p = dst;
614 
615  /* for null */
616  max--;
617  /* skip until next non whitespace char */
618  while ((c = fgetc(f)) != EOF) {
619  if (av_isspace(c))
620  continue;
621 
622  *p++ = c;
623  max--;
624  break;
625  }
626 
627  /* get max bytes or up until next whitespace char */
628  for (; max > 0; max--) {
629  if ((c = fgetc(f)) == EOF)
630  break;
631 
632  if (av_isspace(c))
633  break;
634 
635  *p++ = c;
636  }
637 
638  *p = 0;
639  if (p == dst)
640  return NULL;
641  return p;
642 }
643 
644 #define NEXT_LINE(loop_cond) do { \
645  if (!fgets(line, sizeof(line), f)) { \
646  av_log(ctx, AV_LOG_ERROR, "Unexpected EOF\n"); \
647  return AVERROR_INVALIDDATA; \
648  } \
649 } while (loop_cond)
650 
651 #define NEXT_LINE_OR_GOTO(loop_cond, label) do { \
652  if (!fgets(line, sizeof(line), f)) { \
653  av_log(ctx, AV_LOG_ERROR, "Unexpected EOF\n"); \
654  ret = AVERROR_INVALIDDATA; \
655  goto label; \
656  } \
657 } while (loop_cond)
658 
659 static int allocate_3dlut(AVFilterContext *ctx, int lutsize, int prelut)
660 {
661  LUT3DContext *lut3d = ctx->priv;
662  int i;
663  if (lutsize < 2 || lutsize > MAX_LEVEL) {
664  av_log(ctx, AV_LOG_ERROR, "Too large or invalid 3D LUT size\n");
665  return AVERROR(EINVAL);
666  }
667 
668  av_freep(&lut3d->lut);
669  lut3d->lut = av_malloc_array(lutsize * lutsize * lutsize, sizeof(*lut3d->lut));
670  if (!lut3d->lut)
671  return AVERROR(ENOMEM);
672 
673  if (prelut) {
674  lut3d->prelut.size = PRELUT_SIZE;
675  for (i = 0; i < 3; i++) {
676  av_freep(&lut3d->prelut.lut[i]);
677  lut3d->prelut.lut[i] = av_malloc_array(PRELUT_SIZE, sizeof(*lut3d->prelut.lut[0]));
678  if (!lut3d->prelut.lut[i])
679  return AVERROR(ENOMEM);
680  }
681  } else {
682  lut3d->prelut.size = 0;
683  for (i = 0; i < 3; i++) {
684  av_freep(&lut3d->prelut.lut[i]);
685  }
686  }
687  lut3d->lutsize = lutsize;
688  lut3d->lutsize2 = lutsize * lutsize;
689  return 0;
690 }
691 
692 /* Basically r g and b float values on each line, with a facultative 3DLUTSIZE
693  * directive; seems to be generated by Davinci */
694 static int parse_dat(AVFilterContext *ctx, FILE *f)
695 {
696  LUT3DContext *lut3d = ctx->priv;
697  char line[MAX_LINE_SIZE];
698  int ret, i, j, k, size, size2;
699 
700  lut3d->lutsize = size = 33;
701  size2 = size * size;
702 
704  if (!strncmp(line, "3DLUTSIZE ", 10)) {
705  size = strtol(line + 10, NULL, 0);
706 
708  }
709 
710  ret = allocate_3dlut(ctx, size, 0);
711  if (ret < 0)
712  return ret;
713 
714  for (k = 0; k < size; k++) {
715  for (j = 0; j < size; j++) {
716  for (i = 0; i < size; i++) {
717  struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i];
718  if (k != 0 || j != 0 || i != 0)
720  if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3)
721  return AVERROR_INVALIDDATA;
722  }
723  }
724  }
725  return 0;
726 }
727 
728 /* Iridas format */
729 static int parse_cube(AVFilterContext *ctx, FILE *f)
730 {
731  LUT3DContext *lut3d = ctx->priv;
732  char line[MAX_LINE_SIZE];
733  float min[3] = {0.0, 0.0, 0.0};
734  float max[3] = {1.0, 1.0, 1.0};
735 
736  while (fgets(line, sizeof(line), f)) {
737  if (!strncmp(line, "LUT_3D_SIZE", 11)) {
738  int ret, i, j, k;
739  const int size = strtol(line + 12, NULL, 0);
740  const int size2 = size * size;
741 
742  ret = allocate_3dlut(ctx, size, 0);
743  if (ret < 0)
744  return ret;
745 
746  for (k = 0; k < size; k++) {
747  for (j = 0; j < size; j++) {
748  for (i = 0; i < size; i++) {
749  struct rgbvec *vec = &lut3d->lut[i * size2 + j * size + k];
750 
751  do {
752 try_again:
753  NEXT_LINE(0);
754  if (!strncmp(line, "DOMAIN_", 7)) {
755  float *vals = NULL;
756  if (!strncmp(line + 7, "MIN ", 4)) vals = min;
757  else if (!strncmp(line + 7, "MAX ", 4)) vals = max;
758  if (!vals)
759  return AVERROR_INVALIDDATA;
760  av_sscanf(line + 11, "%f %f %f", vals, vals + 1, vals + 2);
761  av_log(ctx, AV_LOG_DEBUG, "min: %f %f %f | max: %f %f %f\n",
762  min[0], min[1], min[2], max[0], max[1], max[2]);
763  goto try_again;
764  } else if (!strncmp(line, "TITLE", 5)) {
765  goto try_again;
766  }
767  } while (skip_line(line));
768  if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3)
769  return AVERROR_INVALIDDATA;
770  }
771  }
772  }
773  break;
774  }
775  }
776 
777  lut3d->scale.r = av_clipf(1. / (max[0] - min[0]), 0.f, 1.f);
778  lut3d->scale.g = av_clipf(1. / (max[1] - min[1]), 0.f, 1.f);
779  lut3d->scale.b = av_clipf(1. / (max[2] - min[2]), 0.f, 1.f);
780 
781  return 0;
782 }
783 
784 /* Assume 17x17x17 LUT with a 16-bit depth
785  * FIXME: it seems there are various 3dl formats */
786 static int parse_3dl(AVFilterContext *ctx, FILE *f)
787 {
788  char line[MAX_LINE_SIZE];
789  LUT3DContext *lut3d = ctx->priv;
790  int ret, i, j, k;
791  const int size = 17;
792  const int size2 = 17 * 17;
793  const float scale = 16*16*16;
794 
795  lut3d->lutsize = size;
796 
797  ret = allocate_3dlut(ctx, size, 0);
798  if (ret < 0)
799  return ret;
800 
802  for (k = 0; k < size; k++) {
803  for (j = 0; j < size; j++) {
804  for (i = 0; i < size; i++) {
805  int r, g, b;
806  struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i];
807 
809  if (av_sscanf(line, "%d %d %d", &r, &g, &b) != 3)
810  return AVERROR_INVALIDDATA;
811  vec->r = r / scale;
812  vec->g = g / scale;
813  vec->b = b / scale;
814  }
815  }
816  }
817  return 0;
818 }
819 
820 /* Pandora format */
821 static int parse_m3d(AVFilterContext *ctx, FILE *f)
822 {
823  LUT3DContext *lut3d = ctx->priv;
824  float scale;
825  int ret, i, j, k, size, size2, in = -1, out = -1;
826  char line[MAX_LINE_SIZE];
827  uint8_t rgb_map[3] = {0, 1, 2};
828 
829  while (fgets(line, sizeof(line), f)) {
830  if (!strncmp(line, "in", 2)) in = strtol(line + 2, NULL, 0);
831  else if (!strncmp(line, "out", 3)) out = strtol(line + 3, NULL, 0);
832  else if (!strncmp(line, "values", 6)) {
833  const char *p = line + 6;
834 #define SET_COLOR(id) do { \
835  while (av_isspace(*p)) \
836  p++; \
837  switch (*p) { \
838  case 'r': rgb_map[id] = 0; break; \
839  case 'g': rgb_map[id] = 1; break; \
840  case 'b': rgb_map[id] = 2; break; \
841  } \
842  while (*p && !av_isspace(*p)) \
843  p++; \
844 } while (0)
845  SET_COLOR(0);
846  SET_COLOR(1);
847  SET_COLOR(2);
848  break;
849  }
850  }
851 
852  if (in == -1 || out == -1) {
853  av_log(ctx, AV_LOG_ERROR, "in and out must be defined\n");
854  return AVERROR_INVALIDDATA;
855  }
856  if (in < 2 || out < 2 ||
859  av_log(ctx, AV_LOG_ERROR, "invalid in (%d) or out (%d)\n", in, out);
860  return AVERROR_INVALIDDATA;
861  }
862  for (size = 1; size*size*size < in; size++);
863  lut3d->lutsize = size;
864  size2 = size * size;
865 
866  ret = allocate_3dlut(ctx, size, 0);
867  if (ret < 0)
868  return ret;
869 
870  scale = 1. / (out - 1);
871 
872  for (k = 0; k < size; k++) {
873  for (j = 0; j < size; j++) {
874  for (i = 0; i < size; i++) {
875  struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i];
876  float val[3];
877 
878  NEXT_LINE(0);
879  if (av_sscanf(line, "%f %f %f", val, val + 1, val + 2) != 3)
880  return AVERROR_INVALIDDATA;
881  vec->r = val[rgb_map[0]] * scale;
882  vec->g = val[rgb_map[1]] * scale;
883  vec->b = val[rgb_map[2]] * scale;
884  }
885  }
886  }
887  return 0;
888 }
889 
890 static int nearest_sample_index(float *data, float x, int low, int hi)
891 {
892  int mid;
893  if (x < data[low])
894  return low;
895 
896  if (x > data[hi])
897  return hi;
898 
899  for (;;) {
900  av_assert0(x >= data[low]);
901  av_assert0(x <= data[hi]);
902  av_assert0((hi-low) > 0);
903 
904  if (hi - low == 1)
905  return low;
906 
907  mid = (low + hi) / 2;
908 
909  if (x < data[mid])
910  hi = mid;
911  else
912  low = mid;
913  }
914 
915  return 0;
916 }
917 
918 #define NEXT_FLOAT_OR_GOTO(value, label) \
919  if (!fget_next_word(line, sizeof(line) ,f)) { \
920  ret = AVERROR_INVALIDDATA; \
921  goto label; \
922  } \
923  if (av_sscanf(line, "%f", &value) != 1) { \
924  ret = AVERROR_INVALIDDATA; \
925  goto label; \
926  }
927 
929 {
930  LUT3DContext *lut3d = ctx->priv;
931  char line[MAX_LINE_SIZE];
932  float in_min[3] = {0.0, 0.0, 0.0};
933  float in_max[3] = {1.0, 1.0, 1.0};
934  float out_min[3] = {0.0, 0.0, 0.0};
935  float out_max[3] = {1.0, 1.0, 1.0};
936  int inside_metadata = 0, size, size2;
937  int prelut = 0;
938  int ret = 0;
939 
940  int prelut_sizes[3] = {0, 0, 0};
941  float *in_prelut[3] = {NULL, NULL, NULL};
942  float *out_prelut[3] = {NULL, NULL, NULL};
943 
945  if (strncmp(line, "CSPLUTV100", 10)) {
946  av_log(ctx, AV_LOG_ERROR, "Not cineSpace LUT format\n");
947  ret = AVERROR(EINVAL);
948  goto end;
949  }
950 
952  if (strncmp(line, "3D", 2)) {
953  av_log(ctx, AV_LOG_ERROR, "Not 3D LUT format\n");
954  ret = AVERROR(EINVAL);
955  goto end;
956  }
957 
958  while (1) {
960 
961  if (!strncmp(line, "BEGIN METADATA", 14)) {
962  inside_metadata = 1;
963  continue;
964  }
965  if (!strncmp(line, "END METADATA", 12)) {
966  inside_metadata = 0;
967  continue;
968  }
969  if (inside_metadata == 0) {
970  int size_r, size_g, size_b;
971 
972  for (int i = 0; i < 3; i++) {
973  int npoints = strtol(line, NULL, 0);
974 
975  if (npoints > 2) {
976  float v,last;
977 
978  if (npoints > PRELUT_SIZE) {
979  av_log(ctx, AV_LOG_ERROR, "Prelut size too large.\n");
981  goto end;
982  }
983 
984  if (in_prelut[i] || out_prelut[i]) {
985  av_log(ctx, AV_LOG_ERROR, "Invalid file has multiple preluts.\n");
987  goto end;
988  }
989 
990  in_prelut[i] = (float*)av_malloc(npoints * sizeof(float));
991  out_prelut[i] = (float*)av_malloc(npoints * sizeof(float));
992  if (!in_prelut[i] || !out_prelut[i]) {
993  ret = AVERROR(ENOMEM);
994  goto end;
995  }
996 
997  prelut_sizes[i] = npoints;
998  in_min[i] = FLT_MAX;
999  in_max[i] = -FLT_MAX;
1000  out_min[i] = FLT_MAX;
1001  out_max[i] = -FLT_MAX;
1002 
1003  for (int j = 0; j < npoints; j++) {
1004  NEXT_FLOAT_OR_GOTO(v, end)
1005  in_min[i] = FFMIN(in_min[i], v);
1006  in_max[i] = FFMAX(in_max[i], v);
1007  in_prelut[i][j] = v;
1008  if (j > 0 && v < last) {
1009  av_log(ctx, AV_LOG_ERROR, "Invalid file, non increasing prelut.\n");
1010  ret = AVERROR(ENOMEM);
1011  goto end;
1012  }
1013  last = v;
1014  }
1015 
1016  for (int j = 0; j < npoints; j++) {
1017  NEXT_FLOAT_OR_GOTO(v, end)
1018  out_min[i] = FFMIN(out_min[i], v);
1019  out_max[i] = FFMAX(out_max[i], v);
1020  out_prelut[i][j] = v;
1021  }
1022 
1023  } else if (npoints == 2) {
1025  if (av_sscanf(line, "%f %f", &in_min[i], &in_max[i]) != 2) {
1027  goto end;
1028  }
1030  if (av_sscanf(line, "%f %f", &out_min[i], &out_max[i]) != 2) {
1032  goto end;
1033  }
1034 
1035  } else {
1036  av_log(ctx, AV_LOG_ERROR, "Unsupported number of pre-lut points.\n");
1038  goto end;
1039  }
1040 
1042  }
1043 
1044  if (av_sscanf(line, "%d %d %d", &size_r, &size_g, &size_b) != 3) {
1045  ret = AVERROR(EINVAL);
1046  goto end;
1047  }
1048  if (size_r != size_g || size_r != size_b) {
1049  av_log(ctx, AV_LOG_ERROR, "Unsupported size combination: %dx%dx%d.\n", size_r, size_g, size_b);
1051  goto end;
1052  }
1053 
1054  size = size_r;
1055  size2 = size * size;
1056 
1057  if (prelut_sizes[0] && prelut_sizes[1] && prelut_sizes[2])
1058  prelut = 1;
1059 
1060  ret = allocate_3dlut(ctx, size, prelut);
1061  if (ret < 0)
1062  return ret;
1063 
1064  for (int k = 0; k < size; k++) {
1065  for (int j = 0; j < size; j++) {
1066  for (int i = 0; i < size; i++) {
1067  struct rgbvec *vec = &lut3d->lut[i * size2 + j * size + k];
1068 
1070  if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3) {
1072  goto end;
1073  }
1074 
1075  vec->r *= out_max[0] - out_min[0];
1076  vec->g *= out_max[1] - out_min[1];
1077  vec->b *= out_max[2] - out_min[2];
1078  }
1079  }
1080  }
1081 
1082  break;
1083  }
1084  }
1085 
1086  if (prelut) {
1087  for (int c = 0; c < 3; c++) {
1088 
1089  lut3d->prelut.min[c] = in_min[c];
1090  lut3d->prelut.max[c] = in_max[c];
1091  lut3d->prelut.scale[c] = (1.0f / (float)(in_max[c] - in_min[c])) * (lut3d->prelut.size - 1);
1092 
1093  for (int i = 0; i < lut3d->prelut.size; ++i) {
1094  float mix = (float) i / (float)(lut3d->prelut.size - 1);
1095  float x = lerpf(in_min[c], in_max[c], mix), a, b;
1096 
1097  int idx = nearest_sample_index(in_prelut[c], x, 0, prelut_sizes[c]-1);
1098  av_assert0(idx + 1 < prelut_sizes[c]);
1099 
1100  a = out_prelut[c][idx + 0];
1101  b = out_prelut[c][idx + 1];
1102  mix = x - in_prelut[c][idx];
1103 
1104  lut3d->prelut.lut[c][i] = sanitizef(lerpf(a, b, mix));
1105  }
1106  }
1107  lut3d->scale.r = 1.00f;
1108  lut3d->scale.g = 1.00f;
1109  lut3d->scale.b = 1.00f;
1110 
1111  } else {
1112  lut3d->scale.r = av_clipf(1. / (in_max[0] - in_min[0]), 0.f, 1.f);
1113  lut3d->scale.g = av_clipf(1. / (in_max[1] - in_min[1]), 0.f, 1.f);
1114  lut3d->scale.b = av_clipf(1. / (in_max[2] - in_min[2]), 0.f, 1.f);
1115  }
1116 
1117 end:
1118  for (int c = 0; c < 3; c++) {
1119  av_freep(&in_prelut[c]);
1120  av_freep(&out_prelut[c]);
1121  }
1122  return ret;
1123 }
1124 
1126 {
1127  LUT3DContext *lut3d = ctx->priv;
1128  int ret, i, j, k;
1129  const int size2 = size * size;
1130  const float c = 1. / (size - 1);
1131 
1132  ret = allocate_3dlut(ctx, size, 0);
1133  if (ret < 0)
1134  return ret;
1135 
1136  for (k = 0; k < size; k++) {
1137  for (j = 0; j < size; j++) {
1138  for (i = 0; i < size; i++) {
1139  struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i];
1140  vec->r = k * c;
1141  vec->g = j * c;
1142  vec->b = i * c;
1143  }
1144  }
1145  }
1146 
1147  return 0;
1148 }
1149 
1151 {
1152  static const enum AVPixelFormat pix_fmts[] = {
1168  };
1170 }
1171 
1173 {
1174  int depth, is16bit, isfloat, planar;
1175  LUT3DContext *lut3d = inlink->dst->priv;
1177 
1178  depth = desc->comp[0].depth;
1179  is16bit = desc->comp[0].depth > 8;
1180  planar = desc->flags & AV_PIX_FMT_FLAG_PLANAR;
1181  isfloat = desc->flags & AV_PIX_FMT_FLAG_FLOAT;
1182  ff_fill_rgba_map(lut3d->rgba_map, inlink->format);
1183  lut3d->step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit);
1184 
1185 #define SET_FUNC(name) do { \
1186  if (planar && !isfloat) { \
1187  switch (depth) { \
1188  case 8: lut3d->interp = interp_8_##name##_p8; break; \
1189  case 9: lut3d->interp = interp_16_##name##_p9; break; \
1190  case 10: lut3d->interp = interp_16_##name##_p10; break; \
1191  case 12: lut3d->interp = interp_16_##name##_p12; break; \
1192  case 14: lut3d->interp = interp_16_##name##_p14; break; \
1193  case 16: lut3d->interp = interp_16_##name##_p16; break; \
1194  } \
1195  } else if (isfloat) { lut3d->interp = interp_##name##_pf32; \
1196  } else if (is16bit) { lut3d->interp = interp_16_##name; \
1197  } else { lut3d->interp = interp_8_##name; } \
1198 } while (0)
1199 
1200  switch (lut3d->interpolation) {
1201  case INTERPOLATE_NEAREST: SET_FUNC(nearest); break;
1202  case INTERPOLATE_TRILINEAR: SET_FUNC(trilinear); break;
1203  case INTERPOLATE_TETRAHEDRAL: SET_FUNC(tetrahedral); break;
1204  case INTERPOLATE_PYRAMID: SET_FUNC(pyramid); break;
1205  case INTERPOLATE_PRISM: SET_FUNC(prism); break;
1206  default:
1207  av_assert0(0);
1208  }
1209 
1210  return 0;
1211 }
1212 
1214 {
1215  AVFilterContext *ctx = inlink->dst;
1216  LUT3DContext *lut3d = ctx->priv;
1217  AVFilterLink *outlink = inlink->dst->outputs[0];
1218  AVFrame *out;
1219  ThreadData td;
1220 
1221  if (av_frame_is_writable(in)) {
1222  out = in;
1223  } else {
1224  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
1225  if (!out) {
1226  av_frame_free(&in);
1227  return NULL;
1228  }
1229  av_frame_copy_props(out, in);
1230  }
1231 
1232  td.in = in;
1233  td.out = out;
1234  ff_filter_execute(ctx, lut3d->interp, &td, NULL,
1235  FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
1236 
1237  if (out != in)
1238  av_frame_free(&in);
1239 
1240  return out;
1241 }
1242 
1244 {
1245  AVFilterLink *outlink = inlink->dst->outputs[0];
1246  AVFrame *out = apply_lut(inlink, in);
1247  if (!out)
1248  return AVERROR(ENOMEM);
1249  return ff_filter_frame(outlink, out);
1250 }
1251 
1252 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
1253  char *res, int res_len, int flags)
1254 {
1255  int ret;
1256 
1257  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
1258  if (ret < 0)
1259  return ret;
1260 
1261  return config_input(ctx->inputs[0]);
1262 }
1263 
1264 #if CONFIG_LUT3D_FILTER
1265 static const AVOption lut3d_options[] = {
1266  { "file", "set 3D LUT file name", OFFSET(file), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
1268 };
1269 
1270 AVFILTER_DEFINE_CLASS(lut3d);
1271 
1272 static av_cold int lut3d_init(AVFilterContext *ctx)
1273 {
1274  int ret;
1275  FILE *f;
1276  const char *ext;
1277  LUT3DContext *lut3d = ctx->priv;
1278 
1279  lut3d->scale.r = lut3d->scale.g = lut3d->scale.b = 1.f;
1280 
1281  if (!lut3d->file) {
1282  return set_identity_matrix(ctx, 32);
1283  }
1284 
1285  f = av_fopen_utf8(lut3d->file, "r");
1286  if (!f) {
1287  ret = AVERROR(errno);
1288  av_log(ctx, AV_LOG_ERROR, "%s: %s\n", lut3d->file, av_err2str(ret));
1289  return ret;
1290  }
1291 
1292  ext = strrchr(lut3d->file, '.');
1293  if (!ext) {
1294  av_log(ctx, AV_LOG_ERROR, "Unable to guess the format from the extension\n");
1296  goto end;
1297  }
1298  ext++;
1299 
1300  if (!av_strcasecmp(ext, "dat")) {
1301  ret = parse_dat(ctx, f);
1302  } else if (!av_strcasecmp(ext, "3dl")) {
1303  ret = parse_3dl(ctx, f);
1304  } else if (!av_strcasecmp(ext, "cube")) {
1305  ret = parse_cube(ctx, f);
1306  } else if (!av_strcasecmp(ext, "m3d")) {
1307  ret = parse_m3d(ctx, f);
1308  } else if (!av_strcasecmp(ext, "csp")) {
1309  ret = parse_cinespace(ctx, f);
1310  } else {
1311  av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext);
1312  ret = AVERROR(EINVAL);
1313  }
1314 
1315  if (!ret && !lut3d->lutsize) {
1316  av_log(ctx, AV_LOG_ERROR, "3D LUT is empty\n");
1318  }
1319 
1320 end:
1321  fclose(f);
1322  return ret;
1323 }
1324 
1325 static av_cold void lut3d_uninit(AVFilterContext *ctx)
1326 {
1327  LUT3DContext *lut3d = ctx->priv;
1328  int i;
1329  av_freep(&lut3d->lut);
1330 
1331  for (i = 0; i < 3; i++) {
1332  av_freep(&lut3d->prelut.lut[i]);
1333  }
1334 }
1335 
1336 static const AVFilterPad lut3d_inputs[] = {
1337  {
1338  .name = "default",
1339  .type = AVMEDIA_TYPE_VIDEO,
1340  .filter_frame = filter_frame,
1341  .config_props = config_input,
1342  },
1343 };
1344 
1345 static const AVFilterPad lut3d_outputs[] = {
1346  {
1347  .name = "default",
1348  .type = AVMEDIA_TYPE_VIDEO,
1349  },
1350 };
1351 
1352 const AVFilter ff_vf_lut3d = {
1353  .name = "lut3d",
1354  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a 3D LUT."),
1355  .priv_size = sizeof(LUT3DContext),
1356  .init = lut3d_init,
1357  .uninit = lut3d_uninit,
1359  FILTER_INPUTS(lut3d_inputs),
1360  FILTER_OUTPUTS(lut3d_outputs),
1361  .priv_class = &lut3d_class,
1363  .process_command = process_command,
1364 };
1365 #endif
1366 
1367 #if CONFIG_HALDCLUT_FILTER
1368 
1369 static void update_clut_packed(LUT3DContext *lut3d, const AVFrame *frame)
1370 {
1371  const uint8_t *data = frame->data[0];
1372  const int linesize = frame->linesize[0];
1373  const int w = lut3d->clut_width;
1374  const int step = lut3d->clut_step;
1375  const uint8_t *rgba_map = lut3d->clut_rgba_map;
1376  const int level = lut3d->lutsize;
1377  const int level2 = lut3d->lutsize2;
1378 
1379 #define LOAD_CLUT(nbits) do { \
1380  int i, j, k, x = 0, y = 0; \
1381  \
1382  for (k = 0; k < level; k++) { \
1383  for (j = 0; j < level; j++) { \
1384  for (i = 0; i < level; i++) { \
1385  const uint##nbits##_t *src = (const uint##nbits##_t *) \
1386  (data + y*linesize + x*step); \
1387  struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k]; \
1388  vec->r = src[rgba_map[0]] / (float)((1<<(nbits)) - 1); \
1389  vec->g = src[rgba_map[1]] / (float)((1<<(nbits)) - 1); \
1390  vec->b = src[rgba_map[2]] / (float)((1<<(nbits)) - 1); \
1391  if (++x == w) { \
1392  x = 0; \
1393  y++; \
1394  } \
1395  } \
1396  } \
1397  } \
1398 } while (0)
1399 
1400  switch (lut3d->clut_bits) {
1401  case 8: LOAD_CLUT(8); break;
1402  case 16: LOAD_CLUT(16); break;
1403  }
1404 }
1405 
1406 static void update_clut_planar(LUT3DContext *lut3d, const AVFrame *frame)
1407 {
1408  const uint8_t *datag = frame->data[0];
1409  const uint8_t *datab = frame->data[1];
1410  const uint8_t *datar = frame->data[2];
1411  const int glinesize = frame->linesize[0];
1412  const int blinesize = frame->linesize[1];
1413  const int rlinesize = frame->linesize[2];
1414  const int w = lut3d->clut_width;
1415  const int level = lut3d->lutsize;
1416  const int level2 = lut3d->lutsize2;
1417 
1418 #define LOAD_CLUT_PLANAR(nbits, depth) do { \
1419  int i, j, k, x = 0, y = 0; \
1420  \
1421  for (k = 0; k < level; k++) { \
1422  for (j = 0; j < level; j++) { \
1423  for (i = 0; i < level; i++) { \
1424  const uint##nbits##_t *gsrc = (const uint##nbits##_t *) \
1425  (datag + y*glinesize); \
1426  const uint##nbits##_t *bsrc = (const uint##nbits##_t *) \
1427  (datab + y*blinesize); \
1428  const uint##nbits##_t *rsrc = (const uint##nbits##_t *) \
1429  (datar + y*rlinesize); \
1430  struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k]; \
1431  vec->r = gsrc[x] / (float)((1<<(depth)) - 1); \
1432  vec->g = bsrc[x] / (float)((1<<(depth)) - 1); \
1433  vec->b = rsrc[x] / (float)((1<<(depth)) - 1); \
1434  if (++x == w) { \
1435  x = 0; \
1436  y++; \
1437  } \
1438  } \
1439  } \
1440  } \
1441 } while (0)
1442 
1443  switch (lut3d->clut_bits) {
1444  case 8: LOAD_CLUT_PLANAR(8, 8); break;
1445  case 9: LOAD_CLUT_PLANAR(16, 9); break;
1446  case 10: LOAD_CLUT_PLANAR(16, 10); break;
1447  case 12: LOAD_CLUT_PLANAR(16, 12); break;
1448  case 14: LOAD_CLUT_PLANAR(16, 14); break;
1449  case 16: LOAD_CLUT_PLANAR(16, 16); break;
1450  }
1451 }
1452 
1453 static void update_clut_float(LUT3DContext *lut3d, const AVFrame *frame)
1454 {
1455  const uint8_t *datag = frame->data[0];
1456  const uint8_t *datab = frame->data[1];
1457  const uint8_t *datar = frame->data[2];
1458  const int glinesize = frame->linesize[0];
1459  const int blinesize = frame->linesize[1];
1460  const int rlinesize = frame->linesize[2];
1461  const int w = lut3d->clut_width;
1462  const int level = lut3d->lutsize;
1463  const int level2 = lut3d->lutsize2;
1464 
1465  int i, j, k, x = 0, y = 0;
1466 
1467  for (k = 0; k < level; k++) {
1468  for (j = 0; j < level; j++) {
1469  for (i = 0; i < level; i++) {
1470  const float *gsrc = (const float *)(datag + y*glinesize);
1471  const float *bsrc = (const float *)(datab + y*blinesize);
1472  const float *rsrc = (const float *)(datar + y*rlinesize);
1473  struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k];
1474  vec->r = rsrc[x];
1475  vec->g = gsrc[x];
1476  vec->b = bsrc[x];
1477  if (++x == w) {
1478  x = 0;
1479  y++;
1480  }
1481  }
1482  }
1483  }
1484 }
1485 
1486 static int config_output(AVFilterLink *outlink)
1487 {
1488  AVFilterContext *ctx = outlink->src;
1489  LUT3DContext *lut3d = ctx->priv;
1490  int ret;
1491 
1492  ret = ff_framesync_init_dualinput(&lut3d->fs, ctx);
1493  if (ret < 0)
1494  return ret;
1495  outlink->w = ctx->inputs[0]->w;
1496  outlink->h = ctx->inputs[0]->h;
1497  outlink->time_base = ctx->inputs[0]->time_base;
1498  if ((ret = ff_framesync_configure(&lut3d->fs)) < 0)
1499  return ret;
1500  return 0;
1501 }
1502 
1503 static int activate(AVFilterContext *ctx)
1504 {
1505  LUT3DContext *s = ctx->priv;
1506  return ff_framesync_activate(&s->fs);
1507 }
1508 
1509 static int config_clut(AVFilterLink *inlink)
1510 {
1511  int size, level, w, h;
1512  AVFilterContext *ctx = inlink->dst;
1513  LUT3DContext *lut3d = ctx->priv;
1515 
1516  av_assert0(desc);
1517 
1518  lut3d->clut_bits = desc->comp[0].depth;
1519  lut3d->clut_planar = av_pix_fmt_count_planes(inlink->format) > 1;
1520  lut3d->clut_float = desc->flags & AV_PIX_FMT_FLAG_FLOAT;
1521 
1522  lut3d->clut_step = av_get_padded_bits_per_pixel(desc) >> 3;
1523  ff_fill_rgba_map(lut3d->clut_rgba_map, inlink->format);
1524 
1525  if (inlink->w > inlink->h)
1526  av_log(ctx, AV_LOG_INFO, "Padding on the right (%dpx) of the "
1527  "Hald CLUT will be ignored\n", inlink->w - inlink->h);
1528  else if (inlink->w < inlink->h)
1529  av_log(ctx, AV_LOG_INFO, "Padding at the bottom (%dpx) of the "
1530  "Hald CLUT will be ignored\n", inlink->h - inlink->w);
1531  lut3d->clut_width = w = h = FFMIN(inlink->w, inlink->h);
1532 
1533  for (level = 1; level*level*level < w; level++);
1534  size = level*level*level;
1535  if (size != w) {
1536  av_log(ctx, AV_LOG_WARNING, "The Hald CLUT width does not match the level\n");
1537  return AVERROR_INVALIDDATA;
1538  }
1539  av_assert0(w == h && w == size);
1540  level *= level;
1541  if (level > MAX_LEVEL) {
1542  const int max_clut_level = sqrt(MAX_LEVEL);
1543  const int max_clut_size = max_clut_level*max_clut_level*max_clut_level;
1544  av_log(ctx, AV_LOG_ERROR, "Too large Hald CLUT "
1545  "(maximum level is %d, or %dx%d CLUT)\n",
1546  max_clut_level, max_clut_size, max_clut_size);
1547  return AVERROR(EINVAL);
1548  }
1549 
1550  return allocate_3dlut(ctx, level, 0);
1551 }
1552 
1553 static int update_apply_clut(FFFrameSync *fs)
1554 {
1555  AVFilterContext *ctx = fs->parent;
1556  LUT3DContext *lut3d = ctx->priv;
1557  AVFilterLink *inlink = ctx->inputs[0];
1558  AVFrame *master, *second, *out;
1559  int ret;
1560 
1561  ret = ff_framesync_dualinput_get(fs, &master, &second);
1562  if (ret < 0)
1563  return ret;
1564  if (!second)
1565  return ff_filter_frame(ctx->outputs[0], master);
1566  if (lut3d->clut_float)
1567  update_clut_float(ctx->priv, second);
1568  else if (lut3d->clut_planar)
1569  update_clut_planar(ctx->priv, second);
1570  else
1571  update_clut_packed(ctx->priv, second);
1572  out = apply_lut(inlink, master);
1573  return ff_filter_frame(ctx->outputs[0], out);
1574 }
1575 
1576 static av_cold int haldclut_init(AVFilterContext *ctx)
1577 {
1578  LUT3DContext *lut3d = ctx->priv;
1579  lut3d->scale.r = lut3d->scale.g = lut3d->scale.b = 1.f;
1580  lut3d->fs.on_event = update_apply_clut;
1581  return 0;
1582 }
1583 
1584 static av_cold void haldclut_uninit(AVFilterContext *ctx)
1585 {
1586  LUT3DContext *lut3d = ctx->priv;
1587  ff_framesync_uninit(&lut3d->fs);
1588  av_freep(&lut3d->lut);
1589 }
1590 
1591 static const AVOption haldclut_options[] = {
1593 };
1594 
1596 
1597 static const AVFilterPad haldclut_inputs[] = {
1598  {
1599  .name = "main",
1600  .type = AVMEDIA_TYPE_VIDEO,
1601  .config_props = config_input,
1602  },{
1603  .name = "clut",
1604  .type = AVMEDIA_TYPE_VIDEO,
1605  .config_props = config_clut,
1606  },
1607 };
1608 
1609 static const AVFilterPad haldclut_outputs[] = {
1610  {
1611  .name = "default",
1612  .type = AVMEDIA_TYPE_VIDEO,
1613  .config_props = config_output,
1614  },
1615 };
1616 
1617 const AVFilter ff_vf_haldclut = {
1618  .name = "haldclut",
1619  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a Hald CLUT."),
1620  .priv_size = sizeof(LUT3DContext),
1621  .preinit = haldclut_framesync_preinit,
1622  .init = haldclut_init,
1623  .uninit = haldclut_uninit,
1625  .activate = activate,
1626  FILTER_INPUTS(haldclut_inputs),
1627  FILTER_OUTPUTS(haldclut_outputs),
1628  .priv_class = &haldclut_class,
1630  .process_command = process_command,
1631 };
1632 #endif
1633 
1634 #if CONFIG_LUT1D_FILTER
1635 
1636 enum interp_1d_mode {
1637  INTERPOLATE_1D_NEAREST,
1638  INTERPOLATE_1D_LINEAR,
1639  INTERPOLATE_1D_CUBIC,
1640  INTERPOLATE_1D_COSINE,
1641  INTERPOLATE_1D_SPLINE,
1642  NB_INTERP_1D_MODE
1643 };
1644 
1645 #define MAX_1D_LEVEL 65536
1646 
1647 typedef struct LUT1DContext {
1648  const AVClass *class;
1649  char *file;
1650  int interpolation; ///<interp_1d_mode
1651  struct rgbvec scale;
1652  uint8_t rgba_map[4];
1653  int step;
1654  float lut[3][MAX_1D_LEVEL];
1655  int lutsize;
1656  avfilter_action_func *interp;
1657 } LUT1DContext;
1658 
1659 #undef OFFSET
1660 #define OFFSET(x) offsetof(LUT1DContext, x)
1661 
1662 static void set_identity_matrix_1d(LUT1DContext *lut1d, int size)
1663 {
1664  const float c = 1. / (size - 1);
1665  int i;
1666 
1667  lut1d->lutsize = size;
1668  for (i = 0; i < size; i++) {
1669  lut1d->lut[0][i] = i * c;
1670  lut1d->lut[1][i] = i * c;
1671  lut1d->lut[2][i] = i * c;
1672  }
1673 }
1674 
1675 static int parse_cinespace_1d(AVFilterContext *ctx, FILE *f)
1676 {
1677  LUT1DContext *lut1d = ctx->priv;
1678  char line[MAX_LINE_SIZE];
1679  float in_min[3] = {0.0, 0.0, 0.0};
1680  float in_max[3] = {1.0, 1.0, 1.0};
1681  float out_min[3] = {0.0, 0.0, 0.0};
1682  float out_max[3] = {1.0, 1.0, 1.0};
1683  int inside_metadata = 0, size;
1684 
1686  if (strncmp(line, "CSPLUTV100", 10)) {
1687  av_log(ctx, AV_LOG_ERROR, "Not cineSpace LUT format\n");
1688  return AVERROR(EINVAL);
1689  }
1690 
1692  if (strncmp(line, "1D", 2)) {
1693  av_log(ctx, AV_LOG_ERROR, "Not 1D LUT format\n");
1694  return AVERROR(EINVAL);
1695  }
1696 
1697  while (1) {
1699 
1700  if (!strncmp(line, "BEGIN METADATA", 14)) {
1701  inside_metadata = 1;
1702  continue;
1703  }
1704  if (!strncmp(line, "END METADATA", 12)) {
1705  inside_metadata = 0;
1706  continue;
1707  }
1708  if (inside_metadata == 0) {
1709  for (int i = 0; i < 3; i++) {
1710  int npoints = strtol(line, NULL, 0);
1711 
1712  if (npoints != 2) {
1713  av_log(ctx, AV_LOG_ERROR, "Unsupported number of pre-lut points.\n");
1714  return AVERROR_PATCHWELCOME;
1715  }
1716 
1718  if (av_sscanf(line, "%f %f", &in_min[i], &in_max[i]) != 2)
1719  return AVERROR_INVALIDDATA;
1721  if (av_sscanf(line, "%f %f", &out_min[i], &out_max[i]) != 2)
1722  return AVERROR_INVALIDDATA;
1724  }
1725 
1726  size = strtol(line, NULL, 0);
1727 
1728  if (size < 2 || size > MAX_1D_LEVEL) {
1729  av_log(ctx, AV_LOG_ERROR, "Too large or invalid 1D LUT size\n");
1730  return AVERROR(EINVAL);
1731  }
1732 
1733  lut1d->lutsize = size;
1734 
1735  for (int i = 0; i < size; i++) {
1737  if (av_sscanf(line, "%f %f %f", &lut1d->lut[0][i], &lut1d->lut[1][i], &lut1d->lut[2][i]) != 3)
1738  return AVERROR_INVALIDDATA;
1739  lut1d->lut[0][i] *= out_max[0] - out_min[0];
1740  lut1d->lut[1][i] *= out_max[1] - out_min[1];
1741  lut1d->lut[2][i] *= out_max[2] - out_min[2];
1742  }
1743 
1744  break;
1745  }
1746  }
1747 
1748  lut1d->scale.r = av_clipf(1. / (in_max[0] - in_min[0]), 0.f, 1.f);
1749  lut1d->scale.g = av_clipf(1. / (in_max[1] - in_min[1]), 0.f, 1.f);
1750  lut1d->scale.b = av_clipf(1. / (in_max[2] - in_min[2]), 0.f, 1.f);
1751 
1752  return 0;
1753 }
1754 
1755 static int parse_cube_1d(AVFilterContext *ctx, FILE *f)
1756 {
1757  LUT1DContext *lut1d = ctx->priv;
1758  char line[MAX_LINE_SIZE];
1759  float min[3] = {0.0, 0.0, 0.0};
1760  float max[3] = {1.0, 1.0, 1.0};
1761 
1762  while (fgets(line, sizeof(line), f)) {
1763  if (!strncmp(line, "LUT_1D_SIZE", 11)) {
1764  const int size = strtol(line + 12, NULL, 0);
1765  int i;
1766 
1767  if (size < 2 || size > MAX_1D_LEVEL) {
1768  av_log(ctx, AV_LOG_ERROR, "Too large or invalid 1D LUT size\n");
1769  return AVERROR(EINVAL);
1770  }
1771  lut1d->lutsize = size;
1772  for (i = 0; i < size; i++) {
1773  do {
1774 try_again:
1775  NEXT_LINE(0);
1776  if (!strncmp(line, "DOMAIN_", 7)) {
1777  float *vals = NULL;
1778  if (!strncmp(line + 7, "MIN ", 4)) vals = min;
1779  else if (!strncmp(line + 7, "MAX ", 4)) vals = max;
1780  if (!vals)
1781  return AVERROR_INVALIDDATA;
1782  av_sscanf(line + 11, "%f %f %f", vals, vals + 1, vals + 2);
1783  av_log(ctx, AV_LOG_DEBUG, "min: %f %f %f | max: %f %f %f\n",
1784  min[0], min[1], min[2], max[0], max[1], max[2]);
1785  goto try_again;
1786  } else if (!strncmp(line, "LUT_1D_INPUT_RANGE ", 19)) {
1787  av_sscanf(line + 19, "%f %f", min, max);
1788  min[1] = min[2] = min[0];
1789  max[1] = max[2] = max[0];
1790  goto try_again;
1791  } else if (!strncmp(line, "TITLE", 5)) {
1792  goto try_again;
1793  }
1794  } while (skip_line(line));
1795  if (av_sscanf(line, "%f %f %f", &lut1d->lut[0][i], &lut1d->lut[1][i], &lut1d->lut[2][i]) != 3)
1796  return AVERROR_INVALIDDATA;
1797  }
1798  break;
1799  }
1800  }
1801 
1802  lut1d->scale.r = av_clipf(1. / (max[0] - min[0]), 0.f, 1.f);
1803  lut1d->scale.g = av_clipf(1. / (max[1] - min[1]), 0.f, 1.f);
1804  lut1d->scale.b = av_clipf(1. / (max[2] - min[2]), 0.f, 1.f);
1805 
1806  return 0;
1807 }
1808 
1809 static const AVOption lut1d_options[] = {
1810  { "file", "set 1D LUT file name", OFFSET(file), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = TFLAGS },
1811  { "interp", "select interpolation mode", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=INTERPOLATE_1D_LINEAR}, 0, NB_INTERP_1D_MODE-1, TFLAGS, "interp_mode" },
1812  { "nearest", "use values from the nearest defined points", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_NEAREST}, 0, 0, TFLAGS, "interp_mode" },
1813  { "linear", "use values from the linear interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_LINEAR}, 0, 0, TFLAGS, "interp_mode" },
1814  { "cosine", "use values from the cosine interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_COSINE}, 0, 0, TFLAGS, "interp_mode" },
1815  { "cubic", "use values from the cubic interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_CUBIC}, 0, 0, TFLAGS, "interp_mode" },
1816  { "spline", "use values from the spline interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_SPLINE}, 0, 0, TFLAGS, "interp_mode" },
1817  { NULL }
1818 };
1819 
1820 AVFILTER_DEFINE_CLASS(lut1d);
1821 
1822 static inline float interp_1d_nearest(const LUT1DContext *lut1d,
1823  int idx, const float s)
1824 {
1825  return lut1d->lut[idx][NEAR(s)];
1826 }
1827 
1828 #define NEXT1D(x) (FFMIN((int)(x) + 1, lut1d->lutsize - 1))
1829 
1830 static inline float interp_1d_linear(const LUT1DContext *lut1d,
1831  int idx, const float s)
1832 {
1833  const int prev = PREV(s);
1834  const int next = NEXT1D(s);
1835  const float d = s - prev;
1836  const float p = lut1d->lut[idx][prev];
1837  const float n = lut1d->lut[idx][next];
1838 
1839  return lerpf(p, n, d);
1840 }
1841 
1842 static inline float interp_1d_cosine(const LUT1DContext *lut1d,
1843  int idx, const float s)
1844 {
1845  const int prev = PREV(s);
1846  const int next = NEXT1D(s);
1847  const float d = s - prev;
1848  const float p = lut1d->lut[idx][prev];
1849  const float n = lut1d->lut[idx][next];
1850  const float m = (1.f - cosf(d * M_PI)) * .5f;
1851 
1852  return lerpf(p, n, m);
1853 }
1854 
1855 static inline float interp_1d_cubic(const LUT1DContext *lut1d,
1856  int idx, const float s)
1857 {
1858  const int prev = PREV(s);
1859  const int next = NEXT1D(s);
1860  const float mu = s - prev;
1861  float a0, a1, a2, a3, mu2;
1862 
1863  float y0 = lut1d->lut[idx][FFMAX(prev - 1, 0)];
1864  float y1 = lut1d->lut[idx][prev];
1865  float y2 = lut1d->lut[idx][next];
1866  float y3 = lut1d->lut[idx][FFMIN(next + 1, lut1d->lutsize - 1)];
1867 
1868 
1869  mu2 = mu * mu;
1870  a0 = y3 - y2 - y0 + y1;
1871  a1 = y0 - y1 - a0;
1872  a2 = y2 - y0;
1873  a3 = y1;
1874 
1875  return a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3;
1876 }
1877 
1878 static inline float interp_1d_spline(const LUT1DContext *lut1d,
1879  int idx, const float s)
1880 {
1881  const int prev = PREV(s);
1882  const int next = NEXT1D(s);
1883  const float x = s - prev;
1884  float c0, c1, c2, c3;
1885 
1886  float y0 = lut1d->lut[idx][FFMAX(prev - 1, 0)];
1887  float y1 = lut1d->lut[idx][prev];
1888  float y2 = lut1d->lut[idx][next];
1889  float y3 = lut1d->lut[idx][FFMIN(next + 1, lut1d->lutsize - 1)];
1890 
1891  c0 = y1;
1892  c1 = .5f * (y2 - y0);
1893  c2 = y0 - 2.5f * y1 + 2.f * y2 - .5f * y3;
1894  c3 = .5f * (y3 - y0) + 1.5f * (y1 - y2);
1895 
1896  return ((c3 * x + c2) * x + c1) * x + c0;
1897 }
1898 
1899 #define DEFINE_INTERP_FUNC_PLANAR_1D(name, nbits, depth) \
1900 static int interp_1d_##nbits##_##name##_p##depth(AVFilterContext *ctx, \
1901  void *arg, int jobnr, \
1902  int nb_jobs) \
1903 { \
1904  int x, y; \
1905  const LUT1DContext *lut1d = ctx->priv; \
1906  const ThreadData *td = arg; \
1907  const AVFrame *in = td->in; \
1908  const AVFrame *out = td->out; \
1909  const int direct = out == in; \
1910  const int slice_start = (in->height * jobnr ) / nb_jobs; \
1911  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
1912  uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
1913  uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
1914  uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
1915  uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
1916  const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
1917  const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
1918  const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
1919  const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
1920  const float factor = (1 << depth) - 1; \
1921  const float scale_r = (lut1d->scale.r / factor) * (lut1d->lutsize - 1); \
1922  const float scale_g = (lut1d->scale.g / factor) * (lut1d->lutsize - 1); \
1923  const float scale_b = (lut1d->scale.b / factor) * (lut1d->lutsize - 1); \
1924  \
1925  for (y = slice_start; y < slice_end; y++) { \
1926  uint##nbits##_t *dstg = (uint##nbits##_t *)grow; \
1927  uint##nbits##_t *dstb = (uint##nbits##_t *)brow; \
1928  uint##nbits##_t *dstr = (uint##nbits##_t *)rrow; \
1929  uint##nbits##_t *dsta = (uint##nbits##_t *)arow; \
1930  const uint##nbits##_t *srcg = (const uint##nbits##_t *)srcgrow; \
1931  const uint##nbits##_t *srcb = (const uint##nbits##_t *)srcbrow; \
1932  const uint##nbits##_t *srcr = (const uint##nbits##_t *)srcrrow; \
1933  const uint##nbits##_t *srca = (const uint##nbits##_t *)srcarow; \
1934  for (x = 0; x < in->width; x++) { \
1935  float r = srcr[x] * scale_r; \
1936  float g = srcg[x] * scale_g; \
1937  float b = srcb[x] * scale_b; \
1938  r = interp_1d_##name(lut1d, 0, r); \
1939  g = interp_1d_##name(lut1d, 1, g); \
1940  b = interp_1d_##name(lut1d, 2, b); \
1941  dstr[x] = av_clip_uintp2(r * factor, depth); \
1942  dstg[x] = av_clip_uintp2(g * factor, depth); \
1943  dstb[x] = av_clip_uintp2(b * factor, depth); \
1944  if (!direct && in->linesize[3]) \
1945  dsta[x] = srca[x]; \
1946  } \
1947  grow += out->linesize[0]; \
1948  brow += out->linesize[1]; \
1949  rrow += out->linesize[2]; \
1950  arow += out->linesize[3]; \
1951  srcgrow += in->linesize[0]; \
1952  srcbrow += in->linesize[1]; \
1953  srcrrow += in->linesize[2]; \
1954  srcarow += in->linesize[3]; \
1955  } \
1956  return 0; \
1957 }
1958 
1959 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 8, 8)
1960 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 8, 8)
1961 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 8, 8)
1962 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 8, 8)
1963 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 8, 8)
1964 
1965 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 9)
1966 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 9)
1967 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 9)
1968 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 9)
1969 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 9)
1970 
1971 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 10)
1972 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 10)
1973 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 10)
1974 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 10)
1975 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 10)
1976 
1977 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 12)
1978 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 12)
1979 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 12)
1980 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 12)
1981 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 12)
1982 
1983 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 14)
1984 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 14)
1985 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 14)
1986 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 14)
1987 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 14)
1988 
1989 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 16)
1990 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 16)
1991 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 16)
1992 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 16)
1993 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 16)
1994 
1995 #define DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(name, depth) \
1996 static int interp_1d_##name##_pf##depth(AVFilterContext *ctx, \
1997  void *arg, int jobnr, \
1998  int nb_jobs) \
1999 { \
2000  int x, y; \
2001  const LUT1DContext *lut1d = ctx->priv; \
2002  const ThreadData *td = arg; \
2003  const AVFrame *in = td->in; \
2004  const AVFrame *out = td->out; \
2005  const int direct = out == in; \
2006  const int slice_start = (in->height * jobnr ) / nb_jobs; \
2007  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
2008  uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
2009  uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
2010  uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
2011  uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
2012  const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
2013  const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
2014  const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
2015  const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
2016  const float lutsize = lut1d->lutsize - 1; \
2017  const float scale_r = lut1d->scale.r * lutsize; \
2018  const float scale_g = lut1d->scale.g * lutsize; \
2019  const float scale_b = lut1d->scale.b * lutsize; \
2020  \
2021  for (y = slice_start; y < slice_end; y++) { \
2022  float *dstg = (float *)grow; \
2023  float *dstb = (float *)brow; \
2024  float *dstr = (float *)rrow; \
2025  float *dsta = (float *)arow; \
2026  const float *srcg = (const float *)srcgrow; \
2027  const float *srcb = (const float *)srcbrow; \
2028  const float *srcr = (const float *)srcrrow; \
2029  const float *srca = (const float *)srcarow; \
2030  for (x = 0; x < in->width; x++) { \
2031  float r = av_clipf(sanitizef(srcr[x]) * scale_r, 0.0f, lutsize); \
2032  float g = av_clipf(sanitizef(srcg[x]) * scale_g, 0.0f, lutsize); \
2033  float b = av_clipf(sanitizef(srcb[x]) * scale_b, 0.0f, lutsize); \
2034  r = interp_1d_##name(lut1d, 0, r); \
2035  g = interp_1d_##name(lut1d, 1, g); \
2036  b = interp_1d_##name(lut1d, 2, b); \
2037  dstr[x] = r; \
2038  dstg[x] = g; \
2039  dstb[x] = b; \
2040  if (!direct && in->linesize[3]) \
2041  dsta[x] = srca[x]; \
2042  } \
2043  grow += out->linesize[0]; \
2044  brow += out->linesize[1]; \
2045  rrow += out->linesize[2]; \
2046  arow += out->linesize[3]; \
2047  srcgrow += in->linesize[0]; \
2048  srcbrow += in->linesize[1]; \
2049  srcrrow += in->linesize[2]; \
2050  srcarow += in->linesize[3]; \
2051  } \
2052  return 0; \
2053 }
2054 
2055 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(nearest, 32)
2056 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(linear, 32)
2057 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(cosine, 32)
2058 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(cubic, 32)
2059 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(spline, 32)
2060 
2061 #define DEFINE_INTERP_FUNC_1D(name, nbits) \
2062 static int interp_1d_##nbits##_##name(AVFilterContext *ctx, void *arg, \
2063  int jobnr, int nb_jobs) \
2064 { \
2065  int x, y; \
2066  const LUT1DContext *lut1d = ctx->priv; \
2067  const ThreadData *td = arg; \
2068  const AVFrame *in = td->in; \
2069  const AVFrame *out = td->out; \
2070  const int direct = out == in; \
2071  const int step = lut1d->step; \
2072  const uint8_t r = lut1d->rgba_map[R]; \
2073  const uint8_t g = lut1d->rgba_map[G]; \
2074  const uint8_t b = lut1d->rgba_map[B]; \
2075  const uint8_t a = lut1d->rgba_map[A]; \
2076  const int slice_start = (in->height * jobnr ) / nb_jobs; \
2077  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
2078  uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \
2079  const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \
2080  const float factor = (1 << nbits) - 1; \
2081  const float scale_r = (lut1d->scale.r / factor) * (lut1d->lutsize - 1); \
2082  const float scale_g = (lut1d->scale.g / factor) * (lut1d->lutsize - 1); \
2083  const float scale_b = (lut1d->scale.b / factor) * (lut1d->lutsize - 1); \
2084  \
2085  for (y = slice_start; y < slice_end; y++) { \
2086  uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \
2087  const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \
2088  for (x = 0; x < in->width * step; x += step) { \
2089  float rr = src[x + r] * scale_r; \
2090  float gg = src[x + g] * scale_g; \
2091  float bb = src[x + b] * scale_b; \
2092  rr = interp_1d_##name(lut1d, 0, rr); \
2093  gg = interp_1d_##name(lut1d, 1, gg); \
2094  bb = interp_1d_##name(lut1d, 2, bb); \
2095  dst[x + r] = av_clip_uint##nbits(rr * factor); \
2096  dst[x + g] = av_clip_uint##nbits(gg * factor); \
2097  dst[x + b] = av_clip_uint##nbits(bb * factor); \
2098  if (!direct && step == 4) \
2099  dst[x + a] = src[x + a]; \
2100  } \
2101  dstrow += out->linesize[0]; \
2102  srcrow += in ->linesize[0]; \
2103  } \
2104  return 0; \
2105 }
2106 
2107 DEFINE_INTERP_FUNC_1D(nearest, 8)
2108 DEFINE_INTERP_FUNC_1D(linear, 8)
2109 DEFINE_INTERP_FUNC_1D(cosine, 8)
2110 DEFINE_INTERP_FUNC_1D(cubic, 8)
2111 DEFINE_INTERP_FUNC_1D(spline, 8)
2112 
2113 DEFINE_INTERP_FUNC_1D(nearest, 16)
2114 DEFINE_INTERP_FUNC_1D(linear, 16)
2115 DEFINE_INTERP_FUNC_1D(cosine, 16)
2116 DEFINE_INTERP_FUNC_1D(cubic, 16)
2117 DEFINE_INTERP_FUNC_1D(spline, 16)
2118 
2119 static int config_input_1d(AVFilterLink *inlink)
2120 {
2121  int depth, is16bit, isfloat, planar;
2122  LUT1DContext *lut1d = inlink->dst->priv;
2124 
2125  depth = desc->comp[0].depth;
2126  is16bit = desc->comp[0].depth > 8;
2127  planar = desc->flags & AV_PIX_FMT_FLAG_PLANAR;
2128  isfloat = desc->flags & AV_PIX_FMT_FLAG_FLOAT;
2129  ff_fill_rgba_map(lut1d->rgba_map, inlink->format);
2130  lut1d->step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit);
2131 
2132 #define SET_FUNC_1D(name) do { \
2133  if (planar && !isfloat) { \
2134  switch (depth) { \
2135  case 8: lut1d->interp = interp_1d_8_##name##_p8; break; \
2136  case 9: lut1d->interp = interp_1d_16_##name##_p9; break; \
2137  case 10: lut1d->interp = interp_1d_16_##name##_p10; break; \
2138  case 12: lut1d->interp = interp_1d_16_##name##_p12; break; \
2139  case 14: lut1d->interp = interp_1d_16_##name##_p14; break; \
2140  case 16: lut1d->interp = interp_1d_16_##name##_p16; break; \
2141  } \
2142  } else if (isfloat) { lut1d->interp = interp_1d_##name##_pf32; \
2143  } else if (is16bit) { lut1d->interp = interp_1d_16_##name; \
2144  } else { lut1d->interp = interp_1d_8_##name; } \
2145 } while (0)
2146 
2147  switch (lut1d->interpolation) {
2148  case INTERPOLATE_1D_NEAREST: SET_FUNC_1D(nearest); break;
2149  case INTERPOLATE_1D_LINEAR: SET_FUNC_1D(linear); break;
2150  case INTERPOLATE_1D_COSINE: SET_FUNC_1D(cosine); break;
2151  case INTERPOLATE_1D_CUBIC: SET_FUNC_1D(cubic); break;
2152  case INTERPOLATE_1D_SPLINE: SET_FUNC_1D(spline); break;
2153  default:
2154  av_assert0(0);
2155  }
2156 
2157  return 0;
2158 }
2159 
2160 static av_cold int lut1d_init(AVFilterContext *ctx)
2161 {
2162  int ret;
2163  FILE *f;
2164  const char *ext;
2165  LUT1DContext *lut1d = ctx->priv;
2166 
2167  lut1d->scale.r = lut1d->scale.g = lut1d->scale.b = 1.f;
2168 
2169  if (!lut1d->file) {
2170  set_identity_matrix_1d(lut1d, 32);
2171  return 0;
2172  }
2173 
2174  f = av_fopen_utf8(lut1d->file, "r");
2175  if (!f) {
2176  ret = AVERROR(errno);
2177  av_log(ctx, AV_LOG_ERROR, "%s: %s\n", lut1d->file, av_err2str(ret));
2178  return ret;
2179  }
2180 
2181  ext = strrchr(lut1d->file, '.');
2182  if (!ext) {
2183  av_log(ctx, AV_LOG_ERROR, "Unable to guess the format from the extension\n");
2185  goto end;
2186  }
2187  ext++;
2188 
2189  if (!av_strcasecmp(ext, "cube") || !av_strcasecmp(ext, "1dlut")) {
2190  ret = parse_cube_1d(ctx, f);
2191  } else if (!av_strcasecmp(ext, "csp")) {
2192  ret = parse_cinespace_1d(ctx, f);
2193  } else {
2194  av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext);
2195  ret = AVERROR(EINVAL);
2196  }
2197 
2198  if (!ret && !lut1d->lutsize) {
2199  av_log(ctx, AV_LOG_ERROR, "1D LUT is empty\n");
2201  }
2202 
2203 end:
2204  fclose(f);
2205  return ret;
2206 }
2207 
2208 static AVFrame *apply_1d_lut(AVFilterLink *inlink, AVFrame *in)
2209 {
2210  AVFilterContext *ctx = inlink->dst;
2211  LUT1DContext *lut1d = ctx->priv;
2212  AVFilterLink *outlink = inlink->dst->outputs[0];
2213  AVFrame *out;
2214  ThreadData td;
2215 
2216  if (av_frame_is_writable(in)) {
2217  out = in;
2218  } else {
2219  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
2220  if (!out) {
2221  av_frame_free(&in);
2222  return NULL;
2223  }
2224  av_frame_copy_props(out, in);
2225  }
2226 
2227  td.in = in;
2228  td.out = out;
2229  ff_filter_execute(ctx, lut1d->interp, &td, NULL,
2230  FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
2231 
2232  if (out != in)
2233  av_frame_free(&in);
2234 
2235  return out;
2236 }
2237 
2238 static int filter_frame_1d(AVFilterLink *inlink, AVFrame *in)
2239 {
2240  AVFilterLink *outlink = inlink->dst->outputs[0];
2241  AVFrame *out = apply_1d_lut(inlink, in);
2242  if (!out)
2243  return AVERROR(ENOMEM);
2244  return ff_filter_frame(outlink, out);
2245 }
2246 
2247 static int lut1d_process_command(AVFilterContext *ctx, const char *cmd, const char *args,
2248  char *res, int res_len, int flags)
2249 {
2250  LUT1DContext *lut1d = ctx->priv;
2251  int ret;
2252 
2253  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
2254  if (ret < 0)
2255  return ret;
2256 
2257  ret = lut1d_init(ctx);
2258  if (ret < 0) {
2259  set_identity_matrix_1d(lut1d, 32);
2260  return ret;
2261  }
2262  return config_input_1d(ctx->inputs[0]);
2263 }
2264 
2265 static const AVFilterPad lut1d_inputs[] = {
2266  {
2267  .name = "default",
2268  .type = AVMEDIA_TYPE_VIDEO,
2269  .filter_frame = filter_frame_1d,
2270  .config_props = config_input_1d,
2271  },
2272 };
2273 
2274 static const AVFilterPad lut1d_outputs[] = {
2275  {
2276  .name = "default",
2277  .type = AVMEDIA_TYPE_VIDEO,
2278  },
2279 };
2280 
2281 const AVFilter ff_vf_lut1d = {
2282  .name = "lut1d",
2283  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a 1D LUT."),
2284  .priv_size = sizeof(LUT1DContext),
2285  .init = lut1d_init,
2287  FILTER_INPUTS(lut1d_inputs),
2288  FILTER_OUTPUTS(lut1d_outputs),
2289  .priv_class = &lut1d_class,
2291  .process_command = lut1d_process_command,
2292 };
2293 #endif
apply_lut
static AVFrame * apply_lut(AVFilterLink *inlink, AVFrame *in)
Definition: vf_lut3d.c:1213
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:98
COMMON_OPTIONS
#define COMMON_OPTIONS
Definition: vf_lut3d.c:104
config_input
static int config_input(AVFilterLink *inlink)
Definition: vf_lut3d.c:1172
AV_PIX_FMT_GBRAP16
#define AV_PIX_FMT_GBRAP16
Definition: pixfmt.h:411
PRELUT_SIZE
#define PRELUT_SIZE
Definition: vf_lut3d.c:64
DEFINE_INTERP_FUNC_PLANAR_FLOAT
#define DEFINE_INTERP_FUNC_PLANAR_FLOAT(name, depth)
Definition: vf_lut3d.c:473
MAX_LINE_SIZE
#define MAX_LINE_SIZE
Definition: vf_lut3d.c:601
lerpf
static float lerpf(float v0, float v1, float f)
Definition: vf_lut3d.c:137
ff_framesync_configure
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
Definition: framesync.c:124
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
td
#define td
Definition: regdef.h:70
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
level
uint8_t level
Definition: svq3.c:204
init
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:31
mix
static int mix(int c0, int c1)
Definition: 4xm.c:716
r
const char * r
Definition: vf_curves.c:116
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
parse_m3d
static int parse_m3d(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:821
ff_framesync_uninit
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition: framesync.c:290
out
FILE * out
Definition: movenc.c:54
rgbvec
Definition: vf_lut3d.c:57
NEXT_FLOAT_OR_GOTO
#define NEXT_FLOAT_OR_GOTO(value, label)
Definition: vf_lut3d.c:918
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1019
avfilter_action_func
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:788
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2540
apply_prelut
static struct rgbvec apply_prelut(const Lut3DPreLut *prelut, const struct rgbvec *s)
Definition: vf_lut3d.c:361
lerp
static struct rgbvec lerp(const struct rgbvec *v0, const struct rgbvec *v1, float f)
Definition: vf_lut3d.c:142
bsrc
RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT uint8_t const uint8_t const uint8_t * bsrc
Definition: input.c:398
parse_dat
static int parse_dat(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:694
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
av_strcasecmp
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition: avstring.c:215
AV_PIX_FMT_FLAG_FLOAT
#define AV_PIX_FMT_FLAG_FLOAT
The pixel format contains IEEE-754 floating point values.
Definition: pixdesc.h:158
av_isspace
static av_const int av_isspace(int c)
Locale-independent conversion of ASCII isspace.
Definition: avstring.h:227
LUT3DContext::lutsize2
int lutsize2
Definition: vf_lut3d.c:84
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:112
LUT3DContext::scale
struct rgbvec scale
Definition: vf_lut3d.c:81
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:303
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
w
uint8_t w
Definition: llviddspenc.c:38
av_intfloat32::i
uint32_t i
Definition: intfloat.h:28
AVOption
AVOption.
Definition: opt.h:247
skip_line
static int skip_line(const char *p)
Definition: vf_lut3d.c:603
b
#define b
Definition: input.c:40
data
const char data[16]
Definition: mxf.c:143
linear
static int linear(InterplayACMContext *s, unsigned ind, unsigned col)
Definition: interplayacm.c:131
FRAMESYNC_DEFINE_CLASS
#define FRAMESYNC_DEFINE_CLASS(name, context, field)
Definition: framesync.h:302
float.h
interp_tetrahedral
static struct rgbvec interp_tetrahedral(const LUT3DContext *lut3d, const struct rgbvec *s)
Tetrahedral interpolation.
Definition: vf_lut3d.c:292
AV_PIX_FMT_BGR24
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
AV_PIX_FMT_BGRA
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
preinit
static av_cold int preinit(AVFilterContext *ctx)
Definition: af_aresample.c:46
max
#define max(a, b)
Definition: cuda_runtime.h:33
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
interp_prism
static struct rgbvec interp_prism(const LUT3DContext *lut3d, const struct rgbvec *s)
Definition: vf_lut3d.c:243
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:153
c1
static const uint64_t c1
Definition: murmur3.c:51
FFFrameSync
Frame sync structure.
Definition: framesync.h:146
ThreadData::out
AVFrame * out
Definition: af_adeclick.c:492
parse_cube
static int parse_cube(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:729
intfloat.h
video.h
ff_vf_lut3d
const AVFilter ff_vf_lut3d
MANTISSA_MASK
#define MANTISSA_MASK
Definition: vf_lut3d.c:114
SIGN_MASK
#define SIGN_MASK
Definition: vf_lut3d.c:115
LUT3DContext
Definition: vf_lut3d.c:74
process_command
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: vf_lut3d.c:1252
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
formats.h
Lut3DPreLut::lut
float * lut[3]
Definition: vf_lut3d.c:71
INTERPOLATE_TETRAHEDRAL
@ INTERPOLATE_TETRAHEDRAL
Definition: vf_lut3d.c:51
av_pix_fmt_count_planes
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2580
parse_3dl
static int parse_3dl(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:786
AV_PIX_FMT_GBRP14
#define AV_PIX_FMT_GBRP14
Definition: pixfmt.h:407
AV_PIX_FMT_GBRAP
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
Definition: pixfmt.h:205
v0
#define v0
Definition: regdef.h:26
cosf
#define cosf(x)
Definition: libm.h:78
AV_PIX_FMT_GBRP10
#define AV_PIX_FMT_GBRP10
Definition: pixfmt.h:405
val
static double val(void *priv, double ch)
Definition: aeval.c:76
interp_trilinear
static struct rgbvec interp_trilinear(const LUT3DContext *lut3d, const struct rgbvec *s)
Interpolate using the 8 vertices of a cube.
Definition: vf_lut3d.c:167
gsrc
RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT uint8_t const uint8_t * gsrc
Definition: input.c:398
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:50
a1
#define a1
Definition: regdef.h:47
config_output
static int config_output(AVFilterLink *outlink)
Definition: af_adenorm.c:173
SET_COLOR
#define SET_COLOR(id)
avassert.h
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
LUT3DContext::file
char * file
Definition: vf_lut3d.c:77
av_cold
#define av_cold
Definition: attributes.h:90
av_fopen_utf8
FILE * av_fopen_utf8(const char *path, const char *mode)
Open a file using a UTF-8 filename.
Definition: file_open.c:158
Lut3DPreLut::scale
float scale[3]
Definition: vf_lut3d.c:70
NB_INTERP_MODE
@ NB_INTERP_MODE
Definition: vf_lut3d.c:54
AV_PIX_FMT_GBRAP10
#define AV_PIX_FMT_GBRAP10
Definition: pixfmt.h:409
OFFSET
#define OFFSET(x)
Definition: vf_lut3d.c:101
INTERPOLATE_PRISM
@ INTERPOLATE_PRISM
Definition: vf_lut3d.c:53
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:257
AV_PIX_FMT_GBRAP12
#define AV_PIX_FMT_GBRAP12
Definition: pixfmt.h:410
g
const char * g
Definition: vf_curves.c:117
SET_FUNC
#define SET_FUNC(name)
ff_set_common_formats_from_list
int ff_set_common_formats_from_list(AVFilterContext *ctx, const int *fmts)
Equivalent to ff_set_common_formats(ctx, ff_make_format_list(fmts))
Definition: formats.c:703
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
INTERPOLATE_NEAREST
@ INTERPOLATE_NEAREST
Definition: vf_lut3d.c:49
pix_fmts
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:290
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
ctx
AVFormatContext * ctx
Definition: movenc.c:48
fget_next_word
static char * fget_next_word(char *dst, int max, FILE *f)
Definition: vf_lut3d.c:610
interp_mode
interp_mode
Definition: vf_lut3d.c:48
DEFINE_INTERP_FUNC
#define DEFINE_INTERP_FUNC(name, nbits)
Definition: vf_lut3d.c:540
Lut3DPreLut::size
int size
Definition: vf_lut3d.c:67
f
#define f(width, name)
Definition: cbs_vp9.c:255
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: internal.h:152
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_lut3d.c:1243
AV_PIX_FMT_GBRP16
#define AV_PIX_FMT_GBRP16
Definition: pixfmt.h:408
INTERPOLATE_PYRAMID
@ INTERPOLATE_PYRAMID
Definition: vf_lut3d.c:52
AV_PIX_FMT_RGBA64
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:379
av_sscanf
int av_sscanf(const char *string, const char *format,...)
See libc sscanf manual for more information.
Definition: avsscanf.c:960
prelut_interp_1d_linear
static float prelut_interp_1d_linear(const Lut3DPreLut *prelut, int idx, const float s)
Definition: vf_lut3d.c:347
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
rgbvec::r
float r
Definition: vf_lut3d.c:58
AV_PIX_FMT_BGR48
#define AV_PIX_FMT_BGR48
Definition: pixfmt.h:380
NULL
#define NULL
Definition: coverity.c:32
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:64
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:537
fs
#define fs(width, name, subs,...)
Definition: cbs_vp9.c:259
activate
filter_frame For filters that do not use the activate() callback
av_clipf
#define av_clipf
Definition: common.h:144
AV_PIX_FMT_BGR0
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:230
av_intfloat32
Definition: intfloat.h:27
AV_PIX_FMT_GBRP9
#define AV_PIX_FMT_GBRP9
Definition: pixfmt.h:404
AV_PIX_FMT_ABGR
@ AV_PIX_FMT_ABGR
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
Definition: pixfmt.h:94
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
AV_PIX_FMT_RGB24
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
ff_framesync_init_dualinput
int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent)
Initialize a frame sync structure for dualinput.
Definition: framesync.c:358
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:117
master
const char * master
Definition: vf_curves.c:119
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:2505
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:121
AV_PIX_FMT_GBRPF32
#define AV_PIX_FMT_GBRPF32
Definition: pixfmt.h:418
AV_PIX_FMT_RGB48
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:375
size
int size
Definition: twinvq_data.h:10344
Lut3DPreLut::min
float min[3]
Definition: vf_lut3d.c:68
av_frame_is_writable
int av_frame_is_writable(AVFrame *frame)
Check if the frame data is writable.
Definition: frame.c:473
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:883
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
EXPONENT_MASK
#define EXPONENT_MASK
Definition: vf_lut3d.c:113
line
Definition: graph2dot.c:48
AV_PIX_FMT_RGB0
@ AV_PIX_FMT_RGB0
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:228
set_identity_matrix
static int set_identity_matrix(AVFilterContext *ctx, int size)
Definition: vf_lut3d.c:1125
PREV
#define PREV(x)
Definition: vf_lut3d.c:151
rsrc
RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT RGB2YUV_SHIFT uint8_t const uint8_t const uint8_t const uint8_t * rsrc
Definition: input.c:398
a0
#define a0
Definition: regdef.h:46
interpolation
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:355
M_PI
#define M_PI
Definition: mathematics.h:52
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
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:130
AVFILTER_DEFINE_CLASS
#define AVFILTER_DEFINE_CLASS(fname)
Definition: internal.h:289
AV_PIX_FMT_ARGB
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition: pixfmt.h:92
INTERPOLATE_TRILINEAR
@ INTERPOLATE_TRILINEAR
Definition: vf_lut3d.c:50
AV_PIX_FMT_BGRA64
#define AV_PIX_FMT_BGRA64
Definition: pixfmt.h:384
i
int i
Definition: input.c:406
LUT3DContext::interp
avfilter_action_func * interp
Definition: vf_lut3d.c:80
DEFINE_INTERP_FUNC_PLANAR
#define DEFINE_INTERP_FUNC_PLANAR(name, nbits, depth)
Definition: vf_lut3d.c:375
AV_PIX_FMT_GBRP12
#define AV_PIX_FMT_GBRP12
Definition: pixfmt.h:406
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:32
a2
#define a2
Definition: regdef.h:48
ff_filter_get_nb_threads
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:804
ThreadData
Used for passing data between threads.
Definition: dsddec.c:67
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
Lut3DPreLut::max
float max[3]
Definition: vf_lut3d.c:69
interp_pyramid
static struct rgbvec interp_pyramid(const LUT3DContext *lut3d, const struct rgbvec *s)
Definition: vf_lut3d.c:193
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:56
parse_cinespace
static int parse_cinespace(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:928
Lut3DPreLut
Definition: vf_lut3d.c:66
AVFilter
Filter definition.
Definition: avfilter.h:149
sanitizef
static float sanitizef(float f)
Definition: vf_lut3d.c:117
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:229
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
allocate_3dlut
static int allocate_3dlut(AVFilterContext *ctx, int lutsize, int prelut)
Definition: vf_lut3d.c:659
NEXT_LINE_OR_GOTO
#define NEXT_LINE_OR_GOTO(loop_cond, label)
Definition: vf_lut3d.c:651
query_formats
static int query_formats(AVFilterContext *ctx)
Definition: vf_lut3d.c:1150
rgbvec::g
float g
Definition: vf_lut3d.c:58
ff_vf_haldclut
const AVFilter ff_vf_haldclut
NEXT
#define NEXT(x)
Definition: vf_lut3d.c:152
LUT3DContext::prelut
Lut3DPreLut prelut
Definition: vf_lut3d.c:85
c2
static const uint64_t c2
Definition: murmur3.c:52
framesync.h
rgbvec::b
float b
Definition: vf_lut3d.c:58
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:224
avfilter.h
AV_PIX_FMT_GBRAPF32
#define AV_PIX_FMT_GBRAPF32
Definition: pixfmt.h:419
interp_nearest
static struct rgbvec interp_nearest(const LUT3DContext *lut3d, const struct rgbvec *s)
Get the nearest defined point.
Definition: vf_lut3d.c:157
LUT3DContext::step
int step
Definition: vf_lut3d.c:79
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
file.h
TFLAGS
#define TFLAGS
Definition: vf_lut3d.c:103
AVFilterContext
An instance of a filter.
Definition: avfilter.h:346
NEXT_LINE
#define NEXT_LINE(loop_cond)
Definition: vf_lut3d.c:644
av_intfloat32::f
float f
Definition: intfloat.h:29
AV_PIX_FMT_GBRP
@ AV_PIX_FMT_GBRP
planar GBR 4:4:4 24bpp
Definition: pixfmt.h:158
AVFILTER_FLAG_SLICE_THREADS
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:121
desc
const char * desc
Definition: libsvtav1.c:79
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
FLAGS
#define FLAGS
Definition: vf_lut3d.c:102
ThreadData::in
AVFrame * in
Definition: af_adecorrelate.c:171
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:153
NEAR
#define NEAR(x)
Definition: vf_lut3d.c:150
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
ff_fill_rgba_map
int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
Definition: drawutils.c:33
d
d
Definition: ffmpeg_filter.c:156
AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
#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:138
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
AV_PIX_FMT_0RGB
@ AV_PIX_FMT_0RGB
packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined
Definition: pixfmt.h:227
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
uninit
static av_cold int uninit(AVCodecContext *avctx)
Definition: crystalhd.c:279
h
h
Definition: vp9dsp_template.c:2038
ff_framesync_activate
int ff_framesync_activate(FFFrameSync *fs)
Examine the frames in the filter's input and try to produce output.
Definition: framesync.c:341
ff_vf_lut1d
const AVFilter ff_vf_lut1d
avstring.h
ff_framesync_dualinput_get
int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1)
Definition: framesync.c:376
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:228
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:143
planar
uint8_t pi<< 24) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_U8,(uint64_t)((*(const uint8_t *) pi - 0x80U))<< 56) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8,(*(const uint8_t *) pi - 0x80) *(1.0f/(1<< 7))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8,(*(const uint8_t *) pi - 0x80) *(1.0/(1<< 7))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16,(*(const int16_t *) pi >>8)+0x80) CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S16, *(const int16_t *) pi *(1<< 16)) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S16,(uint64_t)(*(const int16_t *) pi)<< 48) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, *(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, *(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32,(*(const int32_t *) pi >>24)+0x80) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S32,(uint64_t)(*(const int32_t *) pi)<< 32) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, *(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, *(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S64,(*(const int64_t *) pi >>56)+0x80) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S64, *(const int64_t *) pi *(1.0f/(UINT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S64, *(const int64_t *) pi *(1.0/(UINT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_FLT, llrintf(*(const float *) pi *(UINT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31)))) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_DBL, llrint(*(const double *) pi *(UINT64_C(1)<< 63))) #define FMT_PAIR_FUNC(out, in) static conv_func_type *const fmt_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), };static void cpy1(uint8_t **dst, const uint8_t **src, int len){ memcpy(*dst, *src, len);} static void cpy2(uint8_t **dst, const uint8_t **src, int len){ memcpy(*dst, *src, 2 *len);} static void cpy4(uint8_t **dst, const uint8_t **src, int len){ memcpy(*dst, *src, 4 *len);} static void cpy8(uint8_t **dst, const uint8_t **src, int len){ memcpy(*dst, *src, 8 *len);} AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, const int *ch_map, int flags) { 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) return NULL;ctx=av_mallocz(sizeof(*ctx));if(!ctx) return NULL;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)){ case 1:ctx->simd_f=cpy1;break;case 2:ctx->simd_f=cpy2;break;case 4:ctx->simd_f=cpy4;break;case 8: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);return ctx;} void swri_audio_convert_free(AudioConvert **ctx) { av_freep(ctx);} int swri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, int len) { int ch;int off=0;const int os=(out->planar ? 1 :out->ch_count) *out->bps;unsigned misaligned=0;av_assert0(ctx->channels==out->ch_count);if(ctx->in_simd_align_mask) { int planes=in->planar ? in->ch_count :1;unsigned m=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) { int planes=out->planar ? out->ch_count :1;unsigned m=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){ int planes=out->planar ? out->ch_count :1;for(ch=0;ch< planes;ch++){ ctx->simd_f(out->ch+ch,(const uint8_t **) in->ch+ch, off *(out-> planar
Definition: audioconvert.c:56
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:233
a3
#define a3
Definition: regdef.h:49
LUT3DContext::lutsize
int lutsize
Definition: vf_lut3d.c:83
LUT3DContext::lut
struct rgbvec * lut
Definition: vf_lut3d.c:82
LUT3DContext::interpolation
int interpolation
interp_mode
Definition: vf_lut3d.c:76
LUT3DContext::rgba_map
uint8_t rgba_map[4]
Definition: vf_lut3d.c:78
MAX_LEVEL
#define MAX_LEVEL
Definition: vf_lut3d.c:63
min
float min
Definition: vorbis_enc_data.h:429
nearest_sample_index
static int nearest_sample_index(float *data, float x, int low, int hi)
Definition: vf_lut3d.c:890