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