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