FFmpeg
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
vf_lut3d.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Clément Bœsch
3  * Copyright (c) 2018 Paul B Mahol
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /**
23  * @file
24  * 3D Lookup table filter
25  */
26 
27 #include <float.h>
28 
29 #include "config_components.h"
30 
31 #include "libavutil/mem.h"
32 #include "libavutil/opt.h"
33 #include "libavutil/file_open.h"
34 #include "libavutil/intfloat.h"
35 #include "libavutil/avassert.h"
36 #include "libavutil/avstring.h"
37 #include "drawutils.h"
38 #include "filters.h"
39 #include "video.h"
40 #include "lut3d.h"
41 
42 #define R 0
43 #define G 1
44 #define B 2
45 #define A 3
46 
47 #define OFFSET(x) offsetof(LUT3DContext, x)
48 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
49 #define TFLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
50 #define COMMON_OPTIONS \
51  { "interp", "select interpolation mode", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=INTERPOLATE_TETRAHEDRAL}, 0, NB_INTERP_MODE-1, TFLAGS, .unit = "interp_mode" }, \
52  { "nearest", "use values from the nearest defined points", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_NEAREST}, 0, 0, TFLAGS, .unit = "interp_mode" }, \
53  { "trilinear", "interpolate values using the 8 points defining a cube", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_TRILINEAR}, 0, 0, TFLAGS, .unit = "interp_mode" }, \
54  { "tetrahedral", "interpolate values using a tetrahedron", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_TETRAHEDRAL}, 0, 0, TFLAGS, .unit = "interp_mode" }, \
55  { "pyramid", "interpolate values using a pyramid", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_PYRAMID}, 0, 0, TFLAGS, .unit = "interp_mode" }, \
56  { "prism", "interpolate values using a prism", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_PRISM}, 0, 0, TFLAGS, .unit = "interp_mode" }, \
57  { NULL }
58 
59 #define EXPONENT_MASK 0x7F800000
60 #define MANTISSA_MASK 0x007FFFFF
61 #define SIGN_MASK 0x80000000
62 
63 static inline float sanitizef(float f)
64 {
65  union av_intfloat32 t;
66  t.f = f;
67 
68  if ((t.i & EXPONENT_MASK) == EXPONENT_MASK) {
69  if ((t.i & MANTISSA_MASK) != 0) {
70  // NAN
71  return 0.0f;
72  } else if (t.i & SIGN_MASK) {
73  // -INF
74  return -FLT_MAX;
75  } else {
76  // +INF
77  return FLT_MAX;
78  }
79  }
80  return f;
81 }
82 
83 static inline float lerpf(float v0, float v1, float f)
84 {
85  return v0 + (v1 - v0) * f;
86 }
87 
88 static inline struct rgbvec lerp(const struct rgbvec *v0, const struct rgbvec *v1, float f)
89 {
90  struct rgbvec v = {
91  lerpf(v0->r, v1->r, f), lerpf(v0->g, v1->g, f), lerpf(v0->b, v1->b, f)
92  };
93  return v;
94 }
95 
96 #define NEAR(x) ((int)((x) + .5))
97 #define PREV(x) ((int)(x))
98 #define NEXT(x) (FFMIN((int)(x) + 1, lut3d->lutsize - 1))
99 
100 /**
101  * Get the nearest defined point
102  */
103 static inline struct rgbvec interp_nearest(const LUT3DContext *lut3d,
104  const struct rgbvec *s)
105 {
106  return lut3d->lut[NEAR(s->r) * lut3d->lutsize2 + NEAR(s->g) * lut3d->lutsize + NEAR(s->b)];
107 }
108 
109 /**
110  * Interpolate using the 8 vertices of a cube
111  * @see https://en.wikipedia.org/wiki/Trilinear_interpolation
112  */
113 static inline struct rgbvec interp_trilinear(const LUT3DContext *lut3d,
114  const struct rgbvec *s)
115 {
116  const int lutsize2 = lut3d->lutsize2;
117  const int lutsize = lut3d->lutsize;
118  const int prev[] = {PREV(s->r), PREV(s->g), PREV(s->b)};
119  const int next[] = {NEXT(s->r), NEXT(s->g), NEXT(s->b)};
120  const struct rgbvec d = {s->r - prev[0], s->g - prev[1], s->b - prev[2]};
121  const struct rgbvec c000 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + prev[2]];
122  const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
123  const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
124  const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
125  const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
126  const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
127  const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
128  const struct rgbvec c111 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + next[2]];
129  const struct rgbvec c00 = lerp(&c000, &c100, d.r);
130  const struct rgbvec c10 = lerp(&c010, &c110, d.r);
131  const struct rgbvec c01 = lerp(&c001, &c101, d.r);
132  const struct rgbvec c11 = lerp(&c011, &c111, d.r);
133  const struct rgbvec c0 = lerp(&c00, &c10, d.g);
134  const struct rgbvec c1 = lerp(&c01, &c11, d.g);
135  const struct rgbvec c = lerp(&c0, &c1, d.b);
136  return c;
137 }
138 
139 static inline struct rgbvec interp_pyramid(const LUT3DContext *lut3d,
140  const struct rgbvec *s)
141 {
142  const int lutsize2 = lut3d->lutsize2;
143  const int lutsize = lut3d->lutsize;
144  const int prev[] = {PREV(s->r), PREV(s->g), PREV(s->b)};
145  const int next[] = {NEXT(s->r), NEXT(s->g), NEXT(s->b)};
146  const struct rgbvec d = {s->r - prev[0], s->g - prev[1], s->b - prev[2]};
147  const struct rgbvec c000 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + prev[2]];
148  const struct rgbvec c111 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + next[2]];
149  struct rgbvec c;
150 
151  if (d.g > d.r && d.b > d.r) {
152  const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
153  const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
154  const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
155 
156  c.r = c000.r + (c111.r - c011.r) * d.r + (c010.r - c000.r) * d.g + (c001.r - c000.r) * d.b +
157  (c011.r - c001.r - c010.r + c000.r) * d.g * d.b;
158  c.g = c000.g + (c111.g - c011.g) * d.r + (c010.g - c000.g) * d.g + (c001.g - c000.g) * d.b +
159  (c011.g - c001.g - c010.g + c000.g) * d.g * d.b;
160  c.b = c000.b + (c111.b - c011.b) * d.r + (c010.b - c000.b) * d.g + (c001.b - c000.b) * d.b +
161  (c011.b - c001.b - c010.b + c000.b) * d.g * d.b;
162  } else if (d.r > d.g && d.b > d.g) {
163  const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
164  const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
165  const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
166 
167  c.r = c000.r + (c100.r - c000.r) * d.r + (c111.r - c101.r) * d.g + (c001.r - c000.r) * d.b +
168  (c101.r - c001.r - c100.r + c000.r) * d.r * d.b;
169  c.g = c000.g + (c100.g - c000.g) * d.r + (c111.g - c101.g) * d.g + (c001.g - c000.g) * d.b +
170  (c101.g - c001.g - c100.g + c000.g) * d.r * d.b;
171  c.b = c000.b + (c100.b - c000.b) * d.r + (c111.b - c101.b) * d.g + (c001.b - c000.b) * d.b +
172  (c101.b - c001.b - c100.b + c000.b) * d.r * d.b;
173  } else {
174  const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
175  const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
176  const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
177 
178  c.r = c000.r + (c100.r - c000.r) * d.r + (c010.r - c000.r) * d.g + (c111.r - c110.r) * d.b +
179  (c110.r - c100.r - c010.r + c000.r) * d.r * d.g;
180  c.g = c000.g + (c100.g - c000.g) * d.r + (c010.g - c000.g) * d.g + (c111.g - c110.g) * d.b +
181  (c110.g - c100.g - c010.g + c000.g) * d.r * d.g;
182  c.b = c000.b + (c100.b - c000.b) * d.r + (c010.b - c000.b) * d.g + (c111.b - c110.b) * d.b +
183  (c110.b - c100.b - c010.b + c000.b) * d.r * d.g;
184  }
185 
186  return c;
187 }
188 
189 static inline struct rgbvec interp_prism(const LUT3DContext *lut3d,
190  const struct rgbvec *s)
191 {
192  const int lutsize2 = lut3d->lutsize2;
193  const int lutsize = lut3d->lutsize;
194  const int prev[] = {PREV(s->r), PREV(s->g), PREV(s->b)};
195  const int next[] = {NEXT(s->r), NEXT(s->g), NEXT(s->b)};
196  const struct rgbvec d = {s->r - prev[0], s->g - prev[1], s->b - prev[2]};
197  const struct rgbvec c000 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + prev[2]];
198  const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
199  const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
200  const struct rgbvec c111 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + next[2]];
201  struct rgbvec c;
202 
203  if (d.b > d.r) {
204  const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
205  const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
206 
207  c.r = c000.r + (c001.r - c000.r) * d.b + (c101.r - c001.r) * d.r + (c010.r - c000.r) * d.g +
208  (c000.r - c010.r - c001.r + c011.r) * d.b * d.g +
209  (c001.r - c011.r - c101.r + c111.r) * d.r * d.g;
210  c.g = c000.g + (c001.g - c000.g) * d.b + (c101.g - c001.g) * d.r + (c010.g - c000.g) * d.g +
211  (c000.g - c010.g - c001.g + c011.g) * d.b * d.g +
212  (c001.g - c011.g - c101.g + c111.g) * d.r * d.g;
213  c.b = c000.b + (c001.b - c000.b) * d.b + (c101.b - c001.b) * d.r + (c010.b - c000.b) * d.g +
214  (c000.b - c010.b - c001.b + c011.b) * d.b * d.g +
215  (c001.b - c011.b - c101.b + c111.b) * d.r * d.g;
216  } else {
217  const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
218  const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
219 
220  c.r = c000.r + (c101.r - c100.r) * d.b + (c100.r - c000.r) * d.r + (c010.r - c000.r) * d.g +
221  (c100.r - c110.r - c101.r + c111.r) * d.b * d.g +
222  (c000.r - c010.r - c100.r + c110.r) * d.r * d.g;
223  c.g = c000.g + (c101.g - c100.g) * d.b + (c100.g - c000.g) * d.r + (c010.g - c000.g) * d.g +
224  (c100.g - c110.g - c101.g + c111.g) * d.b * d.g +
225  (c000.g - c010.g - c100.g + c110.g) * d.r * d.g;
226  c.b = c000.b + (c101.b - c100.b) * d.b + (c100.b - c000.b) * d.r + (c010.b - c000.b) * d.g +
227  (c100.b - c110.b - c101.b + c111.b) * d.b * d.g +
228  (c000.b - c010.b - c100.b + c110.b) * d.r * d.g;
229  }
230 
231  return c;
232 }
233 
234 /**
235  * Tetrahedral interpolation. Based on code found in Truelight Software Library paper.
236  * @see http://www.filmlight.ltd.uk/pdf/whitepapers/FL-TL-TN-0057-SoftwareLib.pdf
237  */
238 static inline struct rgbvec interp_tetrahedral(const LUT3DContext *lut3d,
239  const struct rgbvec *s)
240 {
241  const int lutsize2 = lut3d->lutsize2;
242  const int lutsize = lut3d->lutsize;
243  const int prev[] = {PREV(s->r), PREV(s->g), PREV(s->b)};
244  const int next[] = {NEXT(s->r), NEXT(s->g), NEXT(s->b)};
245  const struct rgbvec d = {s->r - prev[0], s->g - prev[1], s->b - prev[2]};
246  const struct rgbvec c000 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + prev[2]];
247  const struct rgbvec c111 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + next[2]];
248  struct rgbvec c;
249  if (d.r > d.g) {
250  if (d.g > d.b) {
251  const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
252  const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
253  c.r = (1-d.r) * c000.r + (d.r-d.g) * c100.r + (d.g-d.b) * c110.r + (d.b) * c111.r;
254  c.g = (1-d.r) * c000.g + (d.r-d.g) * c100.g + (d.g-d.b) * c110.g + (d.b) * c111.g;
255  c.b = (1-d.r) * c000.b + (d.r-d.g) * c100.b + (d.g-d.b) * c110.b + (d.b) * c111.b;
256  } else if (d.r > d.b) {
257  const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
258  const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
259  c.r = (1-d.r) * c000.r + (d.r-d.b) * c100.r + (d.b-d.g) * c101.r + (d.g) * c111.r;
260  c.g = (1-d.r) * c000.g + (d.r-d.b) * c100.g + (d.b-d.g) * c101.g + (d.g) * c111.g;
261  c.b = (1-d.r) * c000.b + (d.r-d.b) * c100.b + (d.b-d.g) * c101.b + (d.g) * c111.b;
262  } else {
263  const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
264  const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
265  c.r = (1-d.b) * c000.r + (d.b-d.r) * c001.r + (d.r-d.g) * c101.r + (d.g) * c111.r;
266  c.g = (1-d.b) * c000.g + (d.b-d.r) * c001.g + (d.r-d.g) * c101.g + (d.g) * c111.g;
267  c.b = (1-d.b) * c000.b + (d.b-d.r) * c001.b + (d.r-d.g) * c101.b + (d.g) * c111.b;
268  }
269  } else {
270  if (d.b > d.g) {
271  const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
272  const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
273  c.r = (1-d.b) * c000.r + (d.b-d.g) * c001.r + (d.g-d.r) * c011.r + (d.r) * c111.r;
274  c.g = (1-d.b) * c000.g + (d.b-d.g) * c001.g + (d.g-d.r) * c011.g + (d.r) * c111.g;
275  c.b = (1-d.b) * c000.b + (d.b-d.g) * c001.b + (d.g-d.r) * c011.b + (d.r) * c111.b;
276  } else if (d.b > d.r) {
277  const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
278  const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
279  c.r = (1-d.g) * c000.r + (d.g-d.b) * c010.r + (d.b-d.r) * c011.r + (d.r) * c111.r;
280  c.g = (1-d.g) * c000.g + (d.g-d.b) * c010.g + (d.b-d.r) * c011.g + (d.r) * c111.g;
281  c.b = (1-d.g) * c000.b + (d.g-d.b) * c010.b + (d.b-d.r) * c011.b + (d.r) * c111.b;
282  } else {
283  const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
284  const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
285  c.r = (1-d.g) * c000.r + (d.g-d.r) * c010.r + (d.r-d.b) * c110.r + (d.b) * c111.r;
286  c.g = (1-d.g) * c000.g + (d.g-d.r) * c010.g + (d.r-d.b) * c110.g + (d.b) * c111.g;
287  c.b = (1-d.g) * c000.b + (d.g-d.r) * c010.b + (d.r-d.b) * c110.b + (d.b) * c111.b;
288  }
289  }
290  return c;
291 }
292 
293 static inline float prelut_interp_1d_linear(const Lut3DPreLut *prelut,
294  int idx, const float s)
295 {
296  const int lut_max = prelut->size - 1;
297  const float scaled = (s - prelut->min[idx]) * prelut->scale[idx];
298  const float x = av_clipf(scaled, 0.0f, lut_max);
299  const int prev = PREV(x);
300  const int next = FFMIN((int)(x) + 1, lut_max);
301  const float p = prelut->lut[idx][prev];
302  const float n = prelut->lut[idx][next];
303  const float d = x - (float)prev;
304  return lerpf(p, n, d);
305 }
306 
307 static inline struct rgbvec apply_prelut(const Lut3DPreLut *prelut,
308  const struct rgbvec *s)
309 {
310  struct rgbvec c;
311 
312  if (prelut->size <= 0)
313  return *s;
314 
315  c.r = prelut_interp_1d_linear(prelut, 0, s->r);
316  c.g = prelut_interp_1d_linear(prelut, 1, s->g);
317  c.b = prelut_interp_1d_linear(prelut, 2, s->b);
318  return c;
319 }
320 
321 #define DEFINE_INTERP_FUNC_PLANAR(name, nbits, depth) \
322 static int interp_##nbits##_##name##_p##depth(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
323 { \
324  int x, y; \
325  const LUT3DContext *lut3d = ctx->priv; \
326  const Lut3DPreLut *prelut = &lut3d->prelut; \
327  const ThreadData *td = arg; \
328  const AVFrame *in = td->in; \
329  const AVFrame *out = td->out; \
330  const int direct = out == in; \
331  const int slice_start = (in->height * jobnr ) / nb_jobs; \
332  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
333  uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
334  uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
335  uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
336  uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
337  const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
338  const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
339  const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
340  const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
341  const float lut_max = lut3d->lutsize - 1; \
342  const float scale_f = 1.0f / ((1<<depth) - 1); \
343  const float scale_r = lut3d->scale.r * lut_max; \
344  const float scale_g = lut3d->scale.g * lut_max; \
345  const float scale_b = lut3d->scale.b * lut_max; \
346  \
347  for (y = slice_start; y < slice_end; y++) { \
348  uint##nbits##_t *dstg = (uint##nbits##_t *)grow; \
349  uint##nbits##_t *dstb = (uint##nbits##_t *)brow; \
350  uint##nbits##_t *dstr = (uint##nbits##_t *)rrow; \
351  uint##nbits##_t *dsta = (uint##nbits##_t *)arow; \
352  const uint##nbits##_t *srcg = (const uint##nbits##_t *)srcgrow; \
353  const uint##nbits##_t *srcb = (const uint##nbits##_t *)srcbrow; \
354  const uint##nbits##_t *srcr = (const uint##nbits##_t *)srcrrow; \
355  const uint##nbits##_t *srca = (const uint##nbits##_t *)srcarow; \
356  for (x = 0; x < in->width; x++) { \
357  const struct rgbvec rgb = {srcr[x] * scale_f, \
358  srcg[x] * scale_f, \
359  srcb[x] * scale_f}; \
360  const struct rgbvec prelut_rgb = apply_prelut(prelut, &rgb); \
361  const struct rgbvec scaled_rgb = {av_clipf(prelut_rgb.r * scale_r, 0, lut_max), \
362  av_clipf(prelut_rgb.g * scale_g, 0, lut_max), \
363  av_clipf(prelut_rgb.b * scale_b, 0, lut_max)}; \
364  struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \
365  dstr[x] = av_clip_uintp2(vec.r * (float)((1<<depth) - 1), depth); \
366  dstg[x] = av_clip_uintp2(vec.g * (float)((1<<depth) - 1), depth); \
367  dstb[x] = av_clip_uintp2(vec.b * (float)((1<<depth) - 1), depth); \
368  if (!direct && in->linesize[3]) \
369  dsta[x] = srca[x]; \
370  } \
371  grow += out->linesize[0]; \
372  brow += out->linesize[1]; \
373  rrow += out->linesize[2]; \
374  arow += out->linesize[3]; \
375  srcgrow += in->linesize[0]; \
376  srcbrow += in->linesize[1]; \
377  srcrrow += in->linesize[2]; \
378  srcarow += in->linesize[3]; \
379  } \
380  return 0; \
381 }
382 
383 DEFINE_INTERP_FUNC_PLANAR(nearest, 8, 8)
384 DEFINE_INTERP_FUNC_PLANAR(trilinear, 8, 8)
386 DEFINE_INTERP_FUNC_PLANAR(pyramid, 8, 8)
387 DEFINE_INTERP_FUNC_PLANAR(prism, 8, 8)
388 
389 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 9)
390 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 9)
392 DEFINE_INTERP_FUNC_PLANAR(pyramid, 16, 9)
393 DEFINE_INTERP_FUNC_PLANAR(prism, 16, 9)
394 
395 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 10)
396 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 10)
398 DEFINE_INTERP_FUNC_PLANAR(pyramid, 16, 10)
399 DEFINE_INTERP_FUNC_PLANAR(prism, 16, 10)
400 
401 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 12)
402 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 12)
404 DEFINE_INTERP_FUNC_PLANAR(pyramid, 16, 12)
405 DEFINE_INTERP_FUNC_PLANAR(prism, 16, 12)
406 
407 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 14)
408 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 14)
410 DEFINE_INTERP_FUNC_PLANAR(pyramid, 16, 14)
411 DEFINE_INTERP_FUNC_PLANAR(prism, 16, 14)
412 
413 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 16)
414 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 16)
416 DEFINE_INTERP_FUNC_PLANAR(pyramid, 16, 16)
417 DEFINE_INTERP_FUNC_PLANAR(prism, 16, 16)
418 
419 #define DEFINE_INTERP_FUNC_PLANAR_FLOAT(name, depth) \
420 static int interp_##name##_pf##depth(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
421 { \
422  int x, y; \
423  const LUT3DContext *lut3d = ctx->priv; \
424  const Lut3DPreLut *prelut = &lut3d->prelut; \
425  const ThreadData *td = arg; \
426  const AVFrame *in = td->in; \
427  const AVFrame *out = td->out; \
428  const int direct = out == in; \
429  const int slice_start = (in->height * jobnr ) / nb_jobs; \
430  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
431  uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
432  uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
433  uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
434  uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
435  const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
436  const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
437  const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
438  const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
439  const float lut_max = lut3d->lutsize - 1; \
440  const float scale_r = lut3d->scale.r * lut_max; \
441  const float scale_g = lut3d->scale.g * lut_max; \
442  const float scale_b = lut3d->scale.b * lut_max; \
443  \
444  for (y = slice_start; y < slice_end; y++) { \
445  float *dstg = (float *)grow; \
446  float *dstb = (float *)brow; \
447  float *dstr = (float *)rrow; \
448  float *dsta = (float *)arow; \
449  const float *srcg = (const float *)srcgrow; \
450  const float *srcb = (const float *)srcbrow; \
451  const float *srcr = (const float *)srcrrow; \
452  const float *srca = (const float *)srcarow; \
453  for (x = 0; x < in->width; x++) { \
454  const struct rgbvec rgb = {sanitizef(srcr[x]), \
455  sanitizef(srcg[x]), \
456  sanitizef(srcb[x])}; \
457  const struct rgbvec prelut_rgb = apply_prelut(prelut, &rgb); \
458  const struct rgbvec scaled_rgb = {av_clipf(prelut_rgb.r * scale_r, 0, lut_max), \
459  av_clipf(prelut_rgb.g * scale_g, 0, lut_max), \
460  av_clipf(prelut_rgb.b * scale_b, 0, lut_max)}; \
461  struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \
462  dstr[x] = vec.r; \
463  dstg[x] = vec.g; \
464  dstb[x] = vec.b; \
465  if (!direct && in->linesize[3]) \
466  dsta[x] = srca[x]; \
467  } \
468  grow += out->linesize[0]; \
469  brow += out->linesize[1]; \
470  rrow += out->linesize[2]; \
471  arow += out->linesize[3]; \
472  srcgrow += in->linesize[0]; \
473  srcbrow += in->linesize[1]; \
474  srcrrow += in->linesize[2]; \
475  srcarow += in->linesize[3]; \
476  } \
477  return 0; \
478 }
479 
481 DEFINE_INTERP_FUNC_PLANAR_FLOAT(trilinear, 32)
485 
486 #define DEFINE_INTERP_FUNC(name, nbits) \
487 static int interp_##nbits##_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
488 { \
489  int x, y; \
490  const LUT3DContext *lut3d = ctx->priv; \
491  const Lut3DPreLut *prelut = &lut3d->prelut; \
492  const ThreadData *td = arg; \
493  const AVFrame *in = td->in; \
494  const AVFrame *out = td->out; \
495  const int direct = out == in; \
496  const int step = lut3d->step; \
497  const uint8_t r = lut3d->rgba_map[R]; \
498  const uint8_t g = lut3d->rgba_map[G]; \
499  const uint8_t b = lut3d->rgba_map[B]; \
500  const uint8_t a = lut3d->rgba_map[A]; \
501  const int slice_start = (in->height * jobnr ) / nb_jobs; \
502  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
503  uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \
504  const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \
505  const float lut_max = lut3d->lutsize - 1; \
506  const float scale_f = 1.0f / ((1<<nbits) - 1); \
507  const float scale_r = lut3d->scale.r * lut_max; \
508  const float scale_g = lut3d->scale.g * lut_max; \
509  const float scale_b = lut3d->scale.b * lut_max; \
510  \
511  for (y = slice_start; y < slice_end; y++) { \
512  uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \
513  const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \
514  for (x = 0; x < in->width * step; x += step) { \
515  const struct rgbvec rgb = {src[x + r] * scale_f, \
516  src[x + g] * scale_f, \
517  src[x + b] * scale_f}; \
518  const struct rgbvec prelut_rgb = apply_prelut(prelut, &rgb); \
519  const struct rgbvec scaled_rgb = {av_clipf(prelut_rgb.r * scale_r, 0, lut_max), \
520  av_clipf(prelut_rgb.g * scale_g, 0, lut_max), \
521  av_clipf(prelut_rgb.b * scale_b, 0, lut_max)}; \
522  struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \
523  dst[x + r] = av_clip_uint##nbits(vec.r * (float)((1<<nbits) - 1)); \
524  dst[x + g] = av_clip_uint##nbits(vec.g * (float)((1<<nbits) - 1)); \
525  dst[x + b] = av_clip_uint##nbits(vec.b * (float)((1<<nbits) - 1)); \
526  if (!direct && step == 4) \
527  dst[x + a] = src[x + a]; \
528  } \
529  dstrow += out->linesize[0]; \
530  srcrow += in ->linesize[0]; \
531  } \
532  return 0; \
533 }
534 
535 DEFINE_INTERP_FUNC(nearest, 8)
536 DEFINE_INTERP_FUNC(trilinear, 8)
538 DEFINE_INTERP_FUNC(pyramid, 8)
539 DEFINE_INTERP_FUNC(prism, 8)
540 
541 DEFINE_INTERP_FUNC(nearest, 16)
542 DEFINE_INTERP_FUNC(trilinear, 16)
544 DEFINE_INTERP_FUNC(pyramid, 16)
545 DEFINE_INTERP_FUNC(prism, 16)
546 
547 #define MAX_LINE_SIZE 512
548 
549 static int skip_line(const char *p)
550 {
551  while (*p && av_isspace(*p))
552  p++;
553  return !*p || *p == '#';
554 }
555 
556 static char* fget_next_word(char* dst, int max, FILE* f)
557 {
558  int c;
559  char *p = dst;
560 
561  /* for null */
562  max--;
563  /* skip until next non whitespace char */
564  while ((c = fgetc(f)) != EOF) {
565  if (av_isspace(c))
566  continue;
567 
568  *p++ = c;
569  max--;
570  break;
571  }
572 
573  /* get max bytes or up until next whitespace char */
574  for (; max > 0; max--) {
575  if ((c = fgetc(f)) == EOF)
576  break;
577 
578  if (av_isspace(c))
579  break;
580 
581  *p++ = c;
582  }
583 
584  *p = 0;
585  if (p == dst)
586  return NULL;
587  return p;
588 }
589 
590 #define NEXT_LINE(loop_cond) do { \
591  if (!fgets(line, sizeof(line), f)) { \
592  av_log(ctx, AV_LOG_ERROR, "Unexpected EOF\n"); \
593  return AVERROR_INVALIDDATA; \
594  } \
595 } while (loop_cond)
596 
597 #define NEXT_LINE_OR_GOTO(loop_cond, label) do { \
598  if (!fgets(line, sizeof(line), f)) { \
599  av_log(ctx, AV_LOG_ERROR, "Unexpected EOF\n"); \
600  ret = AVERROR_INVALIDDATA; \
601  goto label; \
602  } \
603 } while (loop_cond)
604 
605 static int allocate_3dlut(AVFilterContext *ctx, int lutsize, int prelut)
606 {
607  LUT3DContext *lut3d = ctx->priv;
608  int i;
609  if (lutsize < 2 || lutsize > MAX_LEVEL) {
610  av_log(ctx, AV_LOG_ERROR, "Too large or invalid 3D LUT size\n");
611  return AVERROR(EINVAL);
612  }
613 
614  av_freep(&lut3d->lut);
615  lut3d->lut = av_malloc_array(lutsize * lutsize * lutsize, sizeof(*lut3d->lut));
616  if (!lut3d->lut)
617  return AVERROR(ENOMEM);
618 
619  if (prelut) {
620  lut3d->prelut.size = PRELUT_SIZE;
621  for (i = 0; i < 3; i++) {
622  av_freep(&lut3d->prelut.lut[i]);
623  lut3d->prelut.lut[i] = av_malloc_array(PRELUT_SIZE, sizeof(*lut3d->prelut.lut[0]));
624  if (!lut3d->prelut.lut[i])
625  return AVERROR(ENOMEM);
626  }
627  } else {
628  lut3d->prelut.size = 0;
629  for (i = 0; i < 3; i++) {
630  av_freep(&lut3d->prelut.lut[i]);
631  }
632  }
633  lut3d->lutsize = lutsize;
634  lut3d->lutsize2 = lutsize * lutsize;
635  return 0;
636 }
637 
638 /* Basically r g and b float values on each line, with a facultative 3DLUTSIZE
639  * directive; seems to be generated by Davinci */
640 static int parse_dat(AVFilterContext *ctx, FILE *f)
641 {
642  LUT3DContext *lut3d = ctx->priv;
643  char line[MAX_LINE_SIZE];
644  int ret, i, j, k, size, size2;
645 
646  lut3d->lutsize = size = 33;
647  size2 = size * size;
648 
650  if (!strncmp(line, "3DLUTSIZE ", 10)) {
651  size = strtol(line + 10, NULL, 0);
652 
654  }
655 
656  ret = allocate_3dlut(ctx, size, 0);
657  if (ret < 0)
658  return ret;
659 
660  for (k = 0; k < size; k++) {
661  for (j = 0; j < size; j++) {
662  for (i = 0; i < size; i++) {
663  struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i];
664  if (k != 0 || j != 0 || i != 0)
666  if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3)
667  return AVERROR_INVALIDDATA;
668  }
669  }
670  }
671  return 0;
672 }
673 
674 /* Iridas format */
675 static int parse_cube(AVFilterContext *ctx, FILE *f)
676 {
677  LUT3DContext *lut3d = ctx->priv;
678  char line[MAX_LINE_SIZE];
679  float min[3] = {0.0, 0.0, 0.0};
680  float max[3] = {1.0, 1.0, 1.0};
681 
682  while (fgets(line, sizeof(line), f)) {
683  if (!strncmp(line, "LUT_3D_SIZE", 11)) {
684  int ret, i, j, k;
685  const int size = strtol(line + 12, NULL, 0);
686  const int size2 = size * size;
687 
688  ret = allocate_3dlut(ctx, size, 0);
689  if (ret < 0)
690  return ret;
691 
692  for (k = 0; k < size; k++) {
693  for (j = 0; j < size; j++) {
694  for (i = 0; i < size; i++) {
695  struct rgbvec *vec = &lut3d->lut[i * size2 + j * size + k];
696 
697  do {
698 try_again:
699  NEXT_LINE(0);
700  if (!strncmp(line, "DOMAIN_", 7)) {
701  float *vals = NULL;
702  if (!strncmp(line + 7, "MIN ", 4)) vals = min;
703  else if (!strncmp(line + 7, "MAX ", 4)) vals = max;
704  if (!vals)
705  return AVERROR_INVALIDDATA;
706  if (av_sscanf(line + 11, "%f %f %f", vals, vals + 1, vals + 2) != 3)
707  return AVERROR_INVALIDDATA;
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 
1115 #if CONFIG_LUT3D_FILTER || CONFIG_HALDCLUT_FILTER
1116 
1117 static int config_input(AVFilterLink *inlink)
1118 {
1119  int depth, is16bit, isfloat, planar;
1120  LUT3DContext *lut3d = inlink->dst->priv;
1122 
1123  depth = desc->comp[0].depth;
1124  is16bit = desc->comp[0].depth > 8;
1125  planar = desc->flags & AV_PIX_FMT_FLAG_PLANAR;
1126  isfloat = desc->flags & AV_PIX_FMT_FLAG_FLOAT;
1127  ff_fill_rgba_map(lut3d->rgba_map, inlink->format);
1128  lut3d->step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit);
1129 
1130 #define SET_FUNC(name) do { \
1131  if (planar && !isfloat) { \
1132  switch (depth) { \
1133  case 8: lut3d->interp = interp_8_##name##_p8; break; \
1134  case 9: lut3d->interp = interp_16_##name##_p9; break; \
1135  case 10: lut3d->interp = interp_16_##name##_p10; break; \
1136  case 12: lut3d->interp = interp_16_##name##_p12; break; \
1137  case 14: lut3d->interp = interp_16_##name##_p14; break; \
1138  case 16: lut3d->interp = interp_16_##name##_p16; break; \
1139  } \
1140  } else if (isfloat) { lut3d->interp = interp_##name##_pf32; \
1141  } else if (is16bit) { lut3d->interp = interp_16_##name; \
1142  } else { lut3d->interp = interp_8_##name; } \
1143 } while (0)
1144 
1145  switch (lut3d->interpolation) {
1146  case INTERPOLATE_NEAREST: SET_FUNC(nearest); break;
1147  case INTERPOLATE_TRILINEAR: SET_FUNC(trilinear); break;
1148  case INTERPOLATE_TETRAHEDRAL: SET_FUNC(tetrahedral); break;
1149  case INTERPOLATE_PYRAMID: SET_FUNC(pyramid); break;
1150  case INTERPOLATE_PRISM: SET_FUNC(prism); break;
1151  default:
1152  av_assert0(0);
1153  }
1154 
1155 #if ARCH_X86
1156  ff_lut3d_init_x86(lut3d, desc);
1157 #endif
1158 
1159  return 0;
1160 }
1161 
1163 {
1164  AVFilterContext *ctx = inlink->dst;
1165  LUT3DContext *lut3d = ctx->priv;
1166  AVFilterLink *outlink = inlink->dst->outputs[0];
1167  AVFrame *out;
1168  ThreadData td;
1169 
1170  if (av_frame_is_writable(in)) {
1171  out = in;
1172  } else {
1173  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
1174  if (!out) {
1175  av_frame_free(&in);
1176  return NULL;
1177  }
1178  av_frame_copy_props(out, in);
1179  }
1180 
1181  av_frame_side_data_remove_by_props(&out->side_data, &out->nb_side_data,
1183 
1184  td.in = in;
1185  td.out = out;
1186  ff_filter_execute(ctx, lut3d->interp, &td, NULL,
1187  FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
1188 
1189  if (out != in)
1190  av_frame_free(&in);
1191 
1192  return out;
1193 }
1194 
1195 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
1196 {
1197  AVFilterLink *outlink = inlink->dst->outputs[0];
1198  AVFrame *out = apply_lut(inlink, in);
1199  if (!out)
1200  return AVERROR(ENOMEM);
1201  return ff_filter_frame(outlink, out);
1202 }
1203 
1204 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
1205  char *res, int res_len, int flags)
1206 {
1207  int ret;
1208 
1209  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
1210  if (ret < 0)
1211  return ret;
1212 
1213  return config_input(ctx->inputs[0]);
1214 }
1215 
1216 /* These options are shared between several filters;
1217  * &lut3d_haldclut_options[COMMON_OPTIONS_OFFSET] must always
1218  * point to the first of the COMMON_OPTIONS. */
1219 #define COMMON_OPTIONS_OFFSET CONFIG_LUT3D_FILTER
1220 static const AVOption lut3d_haldclut_options[] = {
1221 #if CONFIG_LUT3D_FILTER
1222  { "file", "set 3D LUT file name", OFFSET(file), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
1223 #endif
1224 #if CONFIG_HALDCLUT_FILTER
1225  { "clut", "when to process CLUT", OFFSET(clut), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, .flags = TFLAGS, .unit = "clut" },
1226  { "first", "process only first CLUT, ignore rest", 0, AV_OPT_TYPE_CONST, {.i64=0}, .flags = TFLAGS, .unit = "clut" },
1227  { "all", "process all CLUTs", 0, AV_OPT_TYPE_CONST, {.i64=1}, .flags = TFLAGS, .unit = "clut" },
1228 #endif
1230 };
1231 
1232 #if CONFIG_LUT3D_FILTER
1233 
1234 AVFILTER_DEFINE_CLASS_EXT(lut3d, "lut3d", lut3d_haldclut_options);
1235 
1236 static av_cold int lut3d_init(AVFilterContext *ctx)
1237 {
1238  int ret;
1239  FILE *f;
1240  const char *ext;
1241  LUT3DContext *lut3d = ctx->priv;
1242 
1243  lut3d->scale.r = lut3d->scale.g = lut3d->scale.b = 1.f;
1244 
1245  if (!lut3d->file) {
1246  return set_identity_matrix(ctx, 32);
1247  }
1248 
1249  f = avpriv_fopen_utf8(lut3d->file, "r");
1250  if (!f) {
1251  ret = AVERROR(errno);
1252  av_log(ctx, AV_LOG_ERROR, "%s: %s\n", lut3d->file, av_err2str(ret));
1253  return ret;
1254  }
1255 
1256  ext = strrchr(lut3d->file, '.');
1257  if (!ext) {
1258  av_log(ctx, AV_LOG_ERROR, "Unable to guess the format from the extension\n");
1260  goto end;
1261  }
1262  ext++;
1263 
1264  if (!av_strcasecmp(ext, "dat")) {
1265  ret = parse_dat(ctx, f);
1266  } else if (!av_strcasecmp(ext, "3dl")) {
1267  ret = parse_3dl(ctx, f);
1268  } else if (!av_strcasecmp(ext, "cube")) {
1269  ret = parse_cube(ctx, f);
1270  } else if (!av_strcasecmp(ext, "m3d")) {
1271  ret = parse_m3d(ctx, f);
1272  } else if (!av_strcasecmp(ext, "csp")) {
1273  ret = parse_cinespace(ctx, f);
1274  } else {
1275  av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext);
1276  ret = AVERROR(EINVAL);
1277  }
1278 
1279  if (!ret && !lut3d->lutsize) {
1280  av_log(ctx, AV_LOG_ERROR, "3D LUT is empty\n");
1282  }
1283 
1284 end:
1285  fclose(f);
1286  return ret;
1287 }
1288 
1289 static av_cold void lut3d_uninit(AVFilterContext *ctx)
1290 {
1291  LUT3DContext *lut3d = ctx->priv;
1292  int i;
1293  av_freep(&lut3d->lut);
1294 
1295  for (i = 0; i < 3; i++) {
1296  av_freep(&lut3d->prelut.lut[i]);
1297  }
1298 }
1299 
1300 static const AVFilterPad lut3d_inputs[] = {
1301  {
1302  .name = "default",
1303  .type = AVMEDIA_TYPE_VIDEO,
1304  .filter_frame = filter_frame,
1305  .config_props = config_input,
1306  },
1307 };
1308 
1309 const AVFilter ff_vf_lut3d = {
1310  .name = "lut3d",
1311  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a 3D LUT."),
1312  .priv_size = sizeof(LUT3DContext),
1313  .init = lut3d_init,
1314  .uninit = lut3d_uninit,
1315  FILTER_INPUTS(lut3d_inputs),
1318  .priv_class = &lut3d_class,
1320  .process_command = process_command,
1321 };
1322 #endif
1323 
1324 #if CONFIG_HALDCLUT_FILTER
1325 
1326 static void update_clut_packed(LUT3DContext *lut3d, const AVFrame *frame)
1327 {
1328  const uint8_t *data = frame->data[0];
1329  const ptrdiff_t linesize = frame->linesize[0];
1330  const int w = lut3d->clut_width;
1331  const int step = lut3d->clut_step;
1332  const uint8_t *rgba_map = lut3d->clut_rgba_map;
1333  const int level = lut3d->lutsize;
1334  const int level2 = lut3d->lutsize2;
1335 
1336 #define LOAD_CLUT(nbits) do { \
1337  int i, j, k, x = 0, y = 0; \
1338  \
1339  for (k = 0; k < level; k++) { \
1340  for (j = 0; j < level; j++) { \
1341  for (i = 0; i < level; i++) { \
1342  const uint##nbits##_t *src = (const uint##nbits##_t *) \
1343  (data + y*linesize + x*step); \
1344  struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k]; \
1345  vec->r = src[rgba_map[0]] / (float)((1<<(nbits)) - 1); \
1346  vec->g = src[rgba_map[1]] / (float)((1<<(nbits)) - 1); \
1347  vec->b = src[rgba_map[2]] / (float)((1<<(nbits)) - 1); \
1348  if (++x == w) { \
1349  x = 0; \
1350  y++; \
1351  } \
1352  } \
1353  } \
1354  } \
1355 } while (0)
1356 
1357  switch (lut3d->clut_bits) {
1358  case 8: LOAD_CLUT(8); break;
1359  case 16: LOAD_CLUT(16); break;
1360  }
1361 }
1362 
1363 static void update_clut_planar(LUT3DContext *lut3d, const AVFrame *frame)
1364 {
1365  const uint8_t *datag = frame->data[0];
1366  const uint8_t *datab = frame->data[1];
1367  const uint8_t *datar = frame->data[2];
1368  const ptrdiff_t glinesize = frame->linesize[0];
1369  const ptrdiff_t blinesize = frame->linesize[1];
1370  const ptrdiff_t rlinesize = frame->linesize[2];
1371  const int w = lut3d->clut_width;
1372  const int level = lut3d->lutsize;
1373  const int level2 = lut3d->lutsize2;
1374 
1375 #define LOAD_CLUT_PLANAR(nbits, depth) do { \
1376  int i, j, k, x = 0, y = 0; \
1377  \
1378  for (k = 0; k < level; k++) { \
1379  for (j = 0; j < level; j++) { \
1380  for (i = 0; i < level; i++) { \
1381  const uint##nbits##_t *gsrc = (const uint##nbits##_t *) \
1382  (datag + y*glinesize); \
1383  const uint##nbits##_t *bsrc = (const uint##nbits##_t *) \
1384  (datab + y*blinesize); \
1385  const uint##nbits##_t *rsrc = (const uint##nbits##_t *) \
1386  (datar + y*rlinesize); \
1387  struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k]; \
1388  vec->r = gsrc[x] / (float)((1<<(depth)) - 1); \
1389  vec->g = bsrc[x] / (float)((1<<(depth)) - 1); \
1390  vec->b = rsrc[x] / (float)((1<<(depth)) - 1); \
1391  if (++x == w) { \
1392  x = 0; \
1393  y++; \
1394  } \
1395  } \
1396  } \
1397  } \
1398 } while (0)
1399 
1400  switch (lut3d->clut_bits) {
1401  case 8: LOAD_CLUT_PLANAR(8, 8); break;
1402  case 9: LOAD_CLUT_PLANAR(16, 9); break;
1403  case 10: LOAD_CLUT_PLANAR(16, 10); break;
1404  case 12: LOAD_CLUT_PLANAR(16, 12); break;
1405  case 14: LOAD_CLUT_PLANAR(16, 14); break;
1406  case 16: LOAD_CLUT_PLANAR(16, 16); break;
1407  }
1408 }
1409 
1410 static void update_clut_float(LUT3DContext *lut3d, const AVFrame *frame)
1411 {
1412  const uint8_t *datag = frame->data[0];
1413  const uint8_t *datab = frame->data[1];
1414  const uint8_t *datar = frame->data[2];
1415  const ptrdiff_t glinesize = frame->linesize[0];
1416  const ptrdiff_t blinesize = frame->linesize[1];
1417  const ptrdiff_t rlinesize = frame->linesize[2];
1418  const int w = lut3d->clut_width;
1419  const int level = lut3d->lutsize;
1420  const int level2 = lut3d->lutsize2;
1421 
1422  int i, j, k, x = 0, y = 0;
1423 
1424  for (k = 0; k < level; k++) {
1425  for (j = 0; j < level; j++) {
1426  for (i = 0; i < level; i++) {
1427  const float *gsrc = (const float *)(datag + y*glinesize);
1428  const float *bsrc = (const float *)(datab + y*blinesize);
1429  const float *rsrc = (const float *)(datar + y*rlinesize);
1430  struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k];
1431  vec->r = rsrc[x];
1432  vec->g = gsrc[x];
1433  vec->b = bsrc[x];
1434  if (++x == w) {
1435  x = 0;
1436  y++;
1437  }
1438  }
1439  }
1440  }
1441 }
1442 
1443 static int config_output(AVFilterLink *outlink)
1444 {
1445  AVFilterContext *ctx = outlink->src;
1446  LUT3DContext *lut3d = ctx->priv;
1447  int ret;
1448 
1449  ret = ff_framesync_init_dualinput(&lut3d->fs, ctx);
1450  if (ret < 0)
1451  return ret;
1452  outlink->w = ctx->inputs[0]->w;
1453  outlink->h = ctx->inputs[0]->h;
1454  outlink->time_base = ctx->inputs[0]->time_base;
1455  if ((ret = ff_framesync_configure(&lut3d->fs)) < 0)
1456  return ret;
1457  return 0;
1458 }
1459 
1460 static int activate(AVFilterContext *ctx)
1461 {
1462  LUT3DContext *s = ctx->priv;
1463  return ff_framesync_activate(&s->fs);
1464 }
1465 
1466 static int config_clut(AVFilterLink *inlink)
1467 {
1468  int size, level, w, h;
1469  AVFilterContext *ctx = inlink->dst;
1470  LUT3DContext *lut3d = ctx->priv;
1472 
1473  av_assert0(desc);
1474 
1475  lut3d->clut_bits = desc->comp[0].depth;
1476  lut3d->clut_planar = av_pix_fmt_count_planes(inlink->format) > 1;
1477  lut3d->clut_float = desc->flags & AV_PIX_FMT_FLAG_FLOAT;
1478 
1479  lut3d->clut_step = av_get_padded_bits_per_pixel(desc) >> 3;
1480  ff_fill_rgba_map(lut3d->clut_rgba_map, inlink->format);
1481 
1482  if (inlink->w > inlink->h)
1483  av_log(ctx, AV_LOG_INFO, "Padding on the right (%dpx) of the "
1484  "Hald CLUT will be ignored\n", inlink->w - inlink->h);
1485  else if (inlink->w < inlink->h)
1486  av_log(ctx, AV_LOG_INFO, "Padding at the bottom (%dpx) of the "
1487  "Hald CLUT will be ignored\n", inlink->h - inlink->w);
1488  lut3d->clut_width = w = h = FFMIN(inlink->w, inlink->h);
1489 
1490  for (level = 1; level*level*level < w; level++);
1491  size = level*level*level;
1492  if (size != w) {
1493  av_log(ctx, AV_LOG_WARNING, "The Hald CLUT width does not match the level\n");
1494  return AVERROR_INVALIDDATA;
1495  }
1496  av_assert0(w == h && w == size);
1497  level *= level;
1498  if (level > MAX_LEVEL) {
1499  const int max_clut_level = sqrt(MAX_LEVEL);
1500  const int max_clut_size = max_clut_level*max_clut_level*max_clut_level;
1501  av_log(ctx, AV_LOG_ERROR, "Too large Hald CLUT "
1502  "(maximum level is %d, or %dx%d CLUT)\n",
1503  max_clut_level, max_clut_size, max_clut_size);
1504  return AVERROR(EINVAL);
1505  }
1506 
1507  return allocate_3dlut(ctx, level, 0);
1508 }
1509 
1510 static int update_apply_clut(FFFrameSync *fs)
1511 {
1512  AVFilterContext *ctx = fs->parent;
1513  LUT3DContext *lut3d = ctx->priv;
1514  AVFilterLink *inlink = ctx->inputs[0];
1515  AVFrame *master, *second, *out;
1516  int ret;
1517 
1518  ret = ff_framesync_dualinput_get(fs, &master, &second);
1519  if (ret < 0)
1520  return ret;
1521  if (!second)
1522  return ff_filter_frame(ctx->outputs[0], master);
1523  if (lut3d->clut || !lut3d->got_clut) {
1524  if (lut3d->clut_float)
1525  update_clut_float(ctx->priv, second);
1526  else if (lut3d->clut_planar)
1527  update_clut_planar(ctx->priv, second);
1528  else
1529  update_clut_packed(ctx->priv, second);
1530  lut3d->got_clut = 1;
1531  }
1532  out = apply_lut(inlink, master);
1533  return ff_filter_frame(ctx->outputs[0], out);
1534 }
1535 
1536 static av_cold int haldclut_init(AVFilterContext *ctx)
1537 {
1538  LUT3DContext *lut3d = ctx->priv;
1539  lut3d->scale.r = lut3d->scale.g = lut3d->scale.b = 1.f;
1540  lut3d->fs.on_event = update_apply_clut;
1541  return 0;
1542 }
1543 
1544 static av_cold void haldclut_uninit(AVFilterContext *ctx)
1545 {
1546  LUT3DContext *lut3d = ctx->priv;
1547  ff_framesync_uninit(&lut3d->fs);
1548  av_freep(&lut3d->lut);
1549 }
1550 
1552  &lut3d_haldclut_options[COMMON_OPTIONS_OFFSET]);
1553 
1554 static const AVFilterPad haldclut_inputs[] = {
1555  {
1556  .name = "main",
1557  .type = AVMEDIA_TYPE_VIDEO,
1558  .config_props = config_input,
1559  },{
1560  .name = "clut",
1561  .type = AVMEDIA_TYPE_VIDEO,
1562  .config_props = config_clut,
1563  },
1564 };
1565 
1566 static const AVFilterPad haldclut_outputs[] = {
1567  {
1568  .name = "default",
1569  .type = AVMEDIA_TYPE_VIDEO,
1570  .config_props = config_output,
1571  },
1572 };
1573 
1574 const AVFilter ff_vf_haldclut = {
1575  .name = "haldclut",
1576  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a Hald CLUT."),
1577  .priv_size = sizeof(LUT3DContext),
1578  .preinit = haldclut_framesync_preinit,
1579  .init = haldclut_init,
1580  .uninit = haldclut_uninit,
1581  .activate = activate,
1582  FILTER_INPUTS(haldclut_inputs),
1583  FILTER_OUTPUTS(haldclut_outputs),
1585  .priv_class = &haldclut_class,
1587  .process_command = process_command,
1588 };
1589 #endif
1590 
1591 #endif /* CONFIG_LUT3D_FILTER || CONFIG_HALDCLUT_FILTER */
1592 
1593 #if CONFIG_LUT1D_FILTER
1594 
1595 enum interp_1d_mode {
1596  INTERPOLATE_1D_NEAREST,
1597  INTERPOLATE_1D_LINEAR,
1598  INTERPOLATE_1D_CUBIC,
1599  INTERPOLATE_1D_COSINE,
1600  INTERPOLATE_1D_SPLINE,
1601  NB_INTERP_1D_MODE
1602 };
1603 
1604 #define MAX_1D_LEVEL 65536
1605 
1606 typedef struct LUT1DContext {
1607  const AVClass *class;
1608  char *file;
1609  int interpolation; ///<interp_1d_mode
1610  struct rgbvec scale;
1611  uint8_t rgba_map[4];
1612  int step;
1613  float lut[3][MAX_1D_LEVEL];
1614  int lutsize;
1616 } LUT1DContext;
1617 
1618 #undef OFFSET
1619 #define OFFSET(x) offsetof(LUT1DContext, x)
1620 
1621 static void set_identity_matrix_1d(LUT1DContext *lut1d, int size)
1622 {
1623  const float c = 1. / (size - 1);
1624  int i;
1625 
1626  lut1d->lutsize = size;
1627  for (i = 0; i < size; i++) {
1628  lut1d->lut[0][i] = i * c;
1629  lut1d->lut[1][i] = i * c;
1630  lut1d->lut[2][i] = i * c;
1631  }
1632 }
1633 
1634 static int parse_cinespace_1d(AVFilterContext *ctx, FILE *f)
1635 {
1636  LUT1DContext *lut1d = ctx->priv;
1637  char line[MAX_LINE_SIZE];
1638  float in_min[3] = {0.0, 0.0, 0.0};
1639  float in_max[3] = {1.0, 1.0, 1.0};
1640  float out_min[3] = {0.0, 0.0, 0.0};
1641  float out_max[3] = {1.0, 1.0, 1.0};
1642  int inside_metadata = 0, size;
1643 
1645  if (strncmp(line, "CSPLUTV100", 10)) {
1646  av_log(ctx, AV_LOG_ERROR, "Not cineSpace LUT format\n");
1647  return AVERROR(EINVAL);
1648  }
1649 
1651  if (strncmp(line, "1D", 2)) {
1652  av_log(ctx, AV_LOG_ERROR, "Not 1D LUT format\n");
1653  return AVERROR(EINVAL);
1654  }
1655 
1656  while (1) {
1658 
1659  if (!strncmp(line, "BEGIN METADATA", 14)) {
1660  inside_metadata = 1;
1661  continue;
1662  }
1663  if (!strncmp(line, "END METADATA", 12)) {
1664  inside_metadata = 0;
1665  continue;
1666  }
1667  if (inside_metadata == 0) {
1668  for (int i = 0; i < 3; i++) {
1669  int npoints = strtol(line, NULL, 0);
1670 
1671  if (npoints != 2) {
1672  av_log(ctx, AV_LOG_ERROR, "Unsupported number of pre-lut points.\n");
1673  return AVERROR_PATCHWELCOME;
1674  }
1675 
1677  if (av_sscanf(line, "%f %f", &in_min[i], &in_max[i]) != 2)
1678  return AVERROR_INVALIDDATA;
1680  if (av_sscanf(line, "%f %f", &out_min[i], &out_max[i]) != 2)
1681  return AVERROR_INVALIDDATA;
1683  }
1684 
1685  size = strtol(line, NULL, 0);
1686 
1687  if (size < 2 || size > MAX_1D_LEVEL) {
1688  av_log(ctx, AV_LOG_ERROR, "Too large or invalid 1D LUT size\n");
1689  return AVERROR(EINVAL);
1690  }
1691 
1692  lut1d->lutsize = size;
1693 
1694  for (int i = 0; i < size; i++) {
1696  if (av_sscanf(line, "%f %f %f", &lut1d->lut[0][i], &lut1d->lut[1][i], &lut1d->lut[2][i]) != 3)
1697  return AVERROR_INVALIDDATA;
1698  lut1d->lut[0][i] *= out_max[0] - out_min[0];
1699  lut1d->lut[1][i] *= out_max[1] - out_min[1];
1700  lut1d->lut[2][i] *= out_max[2] - out_min[2];
1701  }
1702 
1703  break;
1704  }
1705  }
1706 
1707  lut1d->scale.r = av_clipf(1. / (in_max[0] - in_min[0]), 0.f, 1.f);
1708  lut1d->scale.g = av_clipf(1. / (in_max[1] - in_min[1]), 0.f, 1.f);
1709  lut1d->scale.b = av_clipf(1. / (in_max[2] - in_min[2]), 0.f, 1.f);
1710 
1711  return 0;
1712 }
1713 
1714 static int parse_cube_1d(AVFilterContext *ctx, FILE *f)
1715 {
1716  LUT1DContext *lut1d = ctx->priv;
1717  char line[MAX_LINE_SIZE];
1718  float min[3] = {0.0, 0.0, 0.0};
1719  float max[3] = {1.0, 1.0, 1.0};
1720 
1721  while (fgets(line, sizeof(line), f)) {
1722  if (!strncmp(line, "LUT_1D_SIZE", 11)) {
1723  const int size = strtol(line + 12, NULL, 0);
1724  int i;
1725 
1726  if (size < 2 || size > MAX_1D_LEVEL) {
1727  av_log(ctx, AV_LOG_ERROR, "Too large or invalid 1D LUT size\n");
1728  return AVERROR(EINVAL);
1729  }
1730  lut1d->lutsize = size;
1731  for (i = 0; i < size; i++) {
1732  do {
1733 try_again:
1734  NEXT_LINE(0);
1735  if (!strncmp(line, "DOMAIN_", 7)) {
1736  float *vals = NULL;
1737  if (!strncmp(line + 7, "MIN ", 4)) vals = min;
1738  else if (!strncmp(line + 7, "MAX ", 4)) vals = max;
1739  if (!vals)
1740  return AVERROR_INVALIDDATA;
1741  if (av_sscanf(line + 11, "%f %f %f", vals, vals + 1, vals + 2) != 3)
1742  return AVERROR_INVALIDDATA;
1743  av_log(ctx, AV_LOG_DEBUG, "min: %f %f %f | max: %f %f %f\n",
1744  min[0], min[1], min[2], max[0], max[1], max[2]);
1745  goto try_again;
1746  } else if (!strncmp(line, "LUT_1D_INPUT_RANGE ", 19)) {
1747  if (av_sscanf(line + 19, "%f %f", min, max) != 2)
1748  return AVERROR_INVALIDDATA;
1749  min[1] = min[2] = min[0];
1750  max[1] = max[2] = max[0];
1751  goto try_again;
1752  } else if (!strncmp(line, "TITLE", 5)) {
1753  goto try_again;
1754  }
1755  } while (skip_line(line));
1756  if (av_sscanf(line, "%f %f %f", &lut1d->lut[0][i], &lut1d->lut[1][i], &lut1d->lut[2][i]) != 3)
1757  return AVERROR_INVALIDDATA;
1758  }
1759  break;
1760  }
1761  }
1762 
1763  lut1d->scale.r = av_clipf(1. / (max[0] - min[0]), 0.f, 1.f);
1764  lut1d->scale.g = av_clipf(1. / (max[1] - min[1]), 0.f, 1.f);
1765  lut1d->scale.b = av_clipf(1. / (max[2] - min[2]), 0.f, 1.f);
1766 
1767  return 0;
1768 }
1769 
1770 static const AVOption lut1d_options[] = {
1771  { "file", "set 1D LUT file name", OFFSET(file), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = TFLAGS },
1772  { "interp", "select interpolation mode", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=INTERPOLATE_1D_LINEAR}, 0, NB_INTERP_1D_MODE-1, TFLAGS, .unit = "interp_mode" },
1773  { "nearest", "use values from the nearest defined points", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_NEAREST}, 0, 0, TFLAGS, .unit = "interp_mode" },
1774  { "linear", "use values from the linear interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_LINEAR}, 0, 0, TFLAGS, .unit = "interp_mode" },
1775  { "cosine", "use values from the cosine interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_COSINE}, 0, 0, TFLAGS, .unit = "interp_mode" },
1776  { "cubic", "use values from the cubic interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_CUBIC}, 0, 0, TFLAGS, .unit = "interp_mode" },
1777  { "spline", "use values from the spline interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_SPLINE}, 0, 0, TFLAGS, .unit = "interp_mode" },
1778  { NULL }
1779 };
1780 
1781 AVFILTER_DEFINE_CLASS(lut1d);
1782 
1783 static inline float interp_1d_nearest(const LUT1DContext *lut1d,
1784  int idx, const float s)
1785 {
1786  return lut1d->lut[idx][NEAR(s)];
1787 }
1788 
1789 #define NEXT1D(x) (FFMIN((int)(x) + 1, lut1d->lutsize - 1))
1790 
1791 static inline float interp_1d_linear(const LUT1DContext *lut1d,
1792  int idx, const float s)
1793 {
1794  const int prev = PREV(s);
1795  const int next = NEXT1D(s);
1796  const float d = s - prev;
1797  const float p = lut1d->lut[idx][prev];
1798  const float n = lut1d->lut[idx][next];
1799 
1800  return lerpf(p, n, d);
1801 }
1802 
1803 static inline float interp_1d_cosine(const LUT1DContext *lut1d,
1804  int idx, const float s)
1805 {
1806  const int prev = PREV(s);
1807  const int next = NEXT1D(s);
1808  const float d = s - prev;
1809  const float p = lut1d->lut[idx][prev];
1810  const float n = lut1d->lut[idx][next];
1811  const float m = (1.f - cosf(d * M_PI)) * .5f;
1812 
1813  return lerpf(p, n, m);
1814 }
1815 
1816 static inline float interp_1d_cubic(const LUT1DContext *lut1d,
1817  int idx, const float s)
1818 {
1819  const int prev = PREV(s);
1820  const int next = NEXT1D(s);
1821  const float mu = s - prev;
1822  float a0, a1, a2, a3, mu2;
1823 
1824  float y0 = lut1d->lut[idx][FFMAX(prev - 1, 0)];
1825  float y1 = lut1d->lut[idx][prev];
1826  float y2 = lut1d->lut[idx][next];
1827  float y3 = lut1d->lut[idx][FFMIN(next + 1, lut1d->lutsize - 1)];
1828 
1829 
1830  mu2 = mu * mu;
1831  a0 = y3 - y2 - y0 + y1;
1832  a1 = y0 - y1 - a0;
1833  a2 = y2 - y0;
1834  a3 = y1;
1835 
1836  return a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3;
1837 }
1838 
1839 static inline float interp_1d_spline(const LUT1DContext *lut1d,
1840  int idx, const float s)
1841 {
1842  const int prev = PREV(s);
1843  const int next = NEXT1D(s);
1844  const float x = s - prev;
1845  float c0, c1, c2, c3;
1846 
1847  float y0 = lut1d->lut[idx][FFMAX(prev - 1, 0)];
1848  float y1 = lut1d->lut[idx][prev];
1849  float y2 = lut1d->lut[idx][next];
1850  float y3 = lut1d->lut[idx][FFMIN(next + 1, lut1d->lutsize - 1)];
1851 
1852  c0 = y1;
1853  c1 = .5f * (y2 - y0);
1854  c2 = y0 - 2.5f * y1 + 2.f * y2 - .5f * y3;
1855  c3 = .5f * (y3 - y0) + 1.5f * (y1 - y2);
1856 
1857  return ((c3 * x + c2) * x + c1) * x + c0;
1858 }
1859 
1860 #define DEFINE_INTERP_FUNC_PLANAR_1D(name, nbits, depth) \
1861 static int interp_1d_##nbits##_##name##_p##depth(AVFilterContext *ctx, \
1862  void *arg, int jobnr, \
1863  int nb_jobs) \
1864 { \
1865  int x, y; \
1866  const LUT1DContext *lut1d = ctx->priv; \
1867  const ThreadData *td = arg; \
1868  const AVFrame *in = td->in; \
1869  const AVFrame *out = td->out; \
1870  const int direct = out == in; \
1871  const int slice_start = (in->height * jobnr ) / nb_jobs; \
1872  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
1873  uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
1874  uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
1875  uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
1876  uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
1877  const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
1878  const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
1879  const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
1880  const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
1881  const float factor = (1 << depth) - 1; \
1882  const float scale_r = (lut1d->scale.r / factor) * (lut1d->lutsize - 1); \
1883  const float scale_g = (lut1d->scale.g / factor) * (lut1d->lutsize - 1); \
1884  const float scale_b = (lut1d->scale.b / factor) * (lut1d->lutsize - 1); \
1885  \
1886  for (y = slice_start; y < slice_end; y++) { \
1887  uint##nbits##_t *dstg = (uint##nbits##_t *)grow; \
1888  uint##nbits##_t *dstb = (uint##nbits##_t *)brow; \
1889  uint##nbits##_t *dstr = (uint##nbits##_t *)rrow; \
1890  uint##nbits##_t *dsta = (uint##nbits##_t *)arow; \
1891  const uint##nbits##_t *srcg = (const uint##nbits##_t *)srcgrow; \
1892  const uint##nbits##_t *srcb = (const uint##nbits##_t *)srcbrow; \
1893  const uint##nbits##_t *srcr = (const uint##nbits##_t *)srcrrow; \
1894  const uint##nbits##_t *srca = (const uint##nbits##_t *)srcarow; \
1895  for (x = 0; x < in->width; x++) { \
1896  float r = srcr[x] * scale_r; \
1897  float g = srcg[x] * scale_g; \
1898  float b = srcb[x] * scale_b; \
1899  r = interp_1d_##name(lut1d, 0, r); \
1900  g = interp_1d_##name(lut1d, 1, g); \
1901  b = interp_1d_##name(lut1d, 2, b); \
1902  dstr[x] = av_clip_uintp2(r * factor, depth); \
1903  dstg[x] = av_clip_uintp2(g * factor, depth); \
1904  dstb[x] = av_clip_uintp2(b * factor, depth); \
1905  if (!direct && in->linesize[3]) \
1906  dsta[x] = srca[x]; \
1907  } \
1908  grow += out->linesize[0]; \
1909  brow += out->linesize[1]; \
1910  rrow += out->linesize[2]; \
1911  arow += out->linesize[3]; \
1912  srcgrow += in->linesize[0]; \
1913  srcbrow += in->linesize[1]; \
1914  srcrrow += in->linesize[2]; \
1915  srcarow += in->linesize[3]; \
1916  } \
1917  return 0; \
1918 }
1919 
1920 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 8, 8)
1921 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 8, 8)
1922 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 8, 8)
1923 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 8, 8)
1924 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 8, 8)
1925 
1926 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 9)
1927 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 9)
1928 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 9)
1929 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 9)
1930 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 9)
1931 
1932 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 10)
1933 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 10)
1934 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 10)
1935 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 10)
1936 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 10)
1937 
1938 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 12)
1939 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 12)
1940 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 12)
1941 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 12)
1942 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 12)
1943 
1944 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 14)
1945 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 14)
1946 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 14)
1947 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 14)
1948 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 14)
1949 
1950 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 16)
1951 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 16)
1952 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 16)
1953 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 16)
1954 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 16)
1955 
1956 #define DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(name, depth) \
1957 static int interp_1d_##name##_pf##depth(AVFilterContext *ctx, \
1958  void *arg, int jobnr, \
1959  int nb_jobs) \
1960 { \
1961  int x, y; \
1962  const LUT1DContext *lut1d = ctx->priv; \
1963  const ThreadData *td = arg; \
1964  const AVFrame *in = td->in; \
1965  const AVFrame *out = td->out; \
1966  const int direct = out == in; \
1967  const int slice_start = (in->height * jobnr ) / nb_jobs; \
1968  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
1969  uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
1970  uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
1971  uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
1972  uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
1973  const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
1974  const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
1975  const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
1976  const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
1977  const float lutsize = lut1d->lutsize - 1; \
1978  const float scale_r = lut1d->scale.r * lutsize; \
1979  const float scale_g = lut1d->scale.g * lutsize; \
1980  const float scale_b = lut1d->scale.b * lutsize; \
1981  \
1982  for (y = slice_start; y < slice_end; y++) { \
1983  float *dstg = (float *)grow; \
1984  float *dstb = (float *)brow; \
1985  float *dstr = (float *)rrow; \
1986  float *dsta = (float *)arow; \
1987  const float *srcg = (const float *)srcgrow; \
1988  const float *srcb = (const float *)srcbrow; \
1989  const float *srcr = (const float *)srcrrow; \
1990  const float *srca = (const float *)srcarow; \
1991  for (x = 0; x < in->width; x++) { \
1992  float r = av_clipf(sanitizef(srcr[x]) * scale_r, 0.0f, lutsize); \
1993  float g = av_clipf(sanitizef(srcg[x]) * scale_g, 0.0f, lutsize); \
1994  float b = av_clipf(sanitizef(srcb[x]) * scale_b, 0.0f, lutsize); \
1995  r = interp_1d_##name(lut1d, 0, r); \
1996  g = interp_1d_##name(lut1d, 1, g); \
1997  b = interp_1d_##name(lut1d, 2, b); \
1998  dstr[x] = r; \
1999  dstg[x] = g; \
2000  dstb[x] = b; \
2001  if (!direct && in->linesize[3]) \
2002  dsta[x] = srca[x]; \
2003  } \
2004  grow += out->linesize[0]; \
2005  brow += out->linesize[1]; \
2006  rrow += out->linesize[2]; \
2007  arow += out->linesize[3]; \
2008  srcgrow += in->linesize[0]; \
2009  srcbrow += in->linesize[1]; \
2010  srcrrow += in->linesize[2]; \
2011  srcarow += in->linesize[3]; \
2012  } \
2013  return 0; \
2014 }
2015 
2016 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(nearest, 32)
2017 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(linear, 32)
2018 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(cosine, 32)
2019 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(cubic, 32)
2020 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(spline, 32)
2021 
2022 #define DEFINE_INTERP_FUNC_1D(name, nbits) \
2023 static int interp_1d_##nbits##_##name(AVFilterContext *ctx, void *arg, \
2024  int jobnr, int nb_jobs) \
2025 { \
2026  int x, y; \
2027  const LUT1DContext *lut1d = ctx->priv; \
2028  const ThreadData *td = arg; \
2029  const AVFrame *in = td->in; \
2030  const AVFrame *out = td->out; \
2031  const int direct = out == in; \
2032  const int step = lut1d->step; \
2033  const uint8_t r = lut1d->rgba_map[R]; \
2034  const uint8_t g = lut1d->rgba_map[G]; \
2035  const uint8_t b = lut1d->rgba_map[B]; \
2036  const uint8_t a = lut1d->rgba_map[A]; \
2037  const int slice_start = (in->height * jobnr ) / nb_jobs; \
2038  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
2039  uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \
2040  const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \
2041  const float factor = (1 << nbits) - 1; \
2042  const float scale_r = (lut1d->scale.r / factor) * (lut1d->lutsize - 1); \
2043  const float scale_g = (lut1d->scale.g / factor) * (lut1d->lutsize - 1); \
2044  const float scale_b = (lut1d->scale.b / factor) * (lut1d->lutsize - 1); \
2045  \
2046  for (y = slice_start; y < slice_end; y++) { \
2047  uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \
2048  const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \
2049  for (x = 0; x < in->width * step; x += step) { \
2050  float rr = src[x + r] * scale_r; \
2051  float gg = src[x + g] * scale_g; \
2052  float bb = src[x + b] * scale_b; \
2053  rr = interp_1d_##name(lut1d, 0, rr); \
2054  gg = interp_1d_##name(lut1d, 1, gg); \
2055  bb = interp_1d_##name(lut1d, 2, bb); \
2056  dst[x + r] = av_clip_uint##nbits(rr * factor); \
2057  dst[x + g] = av_clip_uint##nbits(gg * factor); \
2058  dst[x + b] = av_clip_uint##nbits(bb * factor); \
2059  if (!direct && step == 4) \
2060  dst[x + a] = src[x + a]; \
2061  } \
2062  dstrow += out->linesize[0]; \
2063  srcrow += in ->linesize[0]; \
2064  } \
2065  return 0; \
2066 }
2067 
2068 DEFINE_INTERP_FUNC_1D(nearest, 8)
2069 DEFINE_INTERP_FUNC_1D(linear, 8)
2070 DEFINE_INTERP_FUNC_1D(cosine, 8)
2071 DEFINE_INTERP_FUNC_1D(cubic, 8)
2072 DEFINE_INTERP_FUNC_1D(spline, 8)
2073 
2074 DEFINE_INTERP_FUNC_1D(nearest, 16)
2075 DEFINE_INTERP_FUNC_1D(linear, 16)
2076 DEFINE_INTERP_FUNC_1D(cosine, 16)
2077 DEFINE_INTERP_FUNC_1D(cubic, 16)
2078 DEFINE_INTERP_FUNC_1D(spline, 16)
2079 
2080 static int config_input_1d(AVFilterLink *inlink)
2081 {
2082  int depth, is16bit, isfloat, planar;
2083  LUT1DContext *lut1d = inlink->dst->priv;
2085 
2086  depth = desc->comp[0].depth;
2087  is16bit = desc->comp[0].depth > 8;
2088  planar = desc->flags & AV_PIX_FMT_FLAG_PLANAR;
2089  isfloat = desc->flags & AV_PIX_FMT_FLAG_FLOAT;
2090  ff_fill_rgba_map(lut1d->rgba_map, inlink->format);
2091  lut1d->step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit);
2092 
2093 #define SET_FUNC_1D(name) do { \
2094  if (planar && !isfloat) { \
2095  switch (depth) { \
2096  case 8: lut1d->interp = interp_1d_8_##name##_p8; break; \
2097  case 9: lut1d->interp = interp_1d_16_##name##_p9; break; \
2098  case 10: lut1d->interp = interp_1d_16_##name##_p10; break; \
2099  case 12: lut1d->interp = interp_1d_16_##name##_p12; break; \
2100  case 14: lut1d->interp = interp_1d_16_##name##_p14; break; \
2101  case 16: lut1d->interp = interp_1d_16_##name##_p16; break; \
2102  } \
2103  } else if (isfloat) { lut1d->interp = interp_1d_##name##_pf32; \
2104  } else if (is16bit) { lut1d->interp = interp_1d_16_##name; \
2105  } else { lut1d->interp = interp_1d_8_##name; } \
2106 } while (0)
2107 
2108  switch (lut1d->interpolation) {
2109  case INTERPOLATE_1D_NEAREST: SET_FUNC_1D(nearest); break;
2110  case INTERPOLATE_1D_LINEAR: SET_FUNC_1D(linear); break;
2111  case INTERPOLATE_1D_COSINE: SET_FUNC_1D(cosine); break;
2112  case INTERPOLATE_1D_CUBIC: SET_FUNC_1D(cubic); break;
2113  case INTERPOLATE_1D_SPLINE: SET_FUNC_1D(spline); break;
2114  default:
2115  av_assert0(0);
2116  }
2117 
2118  return 0;
2119 }
2120 
2121 static av_cold int lut1d_init(AVFilterContext *ctx)
2122 {
2123  int ret;
2124  FILE *f;
2125  const char *ext;
2126  LUT1DContext *lut1d = ctx->priv;
2127 
2128  lut1d->scale.r = lut1d->scale.g = lut1d->scale.b = 1.f;
2129 
2130  if (!lut1d->file) {
2131  set_identity_matrix_1d(lut1d, 32);
2132  return 0;
2133  }
2134 
2135  f = avpriv_fopen_utf8(lut1d->file, "r");
2136  if (!f) {
2137  ret = AVERROR(errno);
2138  av_log(ctx, AV_LOG_ERROR, "%s: %s\n", lut1d->file, av_err2str(ret));
2139  return ret;
2140  }
2141 
2142  ext = strrchr(lut1d->file, '.');
2143  if (!ext) {
2144  av_log(ctx, AV_LOG_ERROR, "Unable to guess the format from the extension\n");
2146  goto end;
2147  }
2148  ext++;
2149 
2150  if (!av_strcasecmp(ext, "cube") || !av_strcasecmp(ext, "1dlut")) {
2151  ret = parse_cube_1d(ctx, f);
2152  } else if (!av_strcasecmp(ext, "csp")) {
2153  ret = parse_cinespace_1d(ctx, f);
2154  } else {
2155  av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext);
2156  ret = AVERROR(EINVAL);
2157  }
2158 
2159  if (!ret && !lut1d->lutsize) {
2160  av_log(ctx, AV_LOG_ERROR, "1D LUT is empty\n");
2162  }
2163 
2164 end:
2165  fclose(f);
2166  return ret;
2167 }
2168 
2169 static AVFrame *apply_1d_lut(AVFilterLink *inlink, AVFrame *in)
2170 {
2171  AVFilterContext *ctx = inlink->dst;
2172  LUT1DContext *lut1d = ctx->priv;
2173  AVFilterLink *outlink = inlink->dst->outputs[0];
2174  AVFrame *out;
2175  ThreadData td;
2176 
2177  if (av_frame_is_writable(in)) {
2178  out = in;
2179  } else {
2180  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
2181  if (!out) {
2182  av_frame_free(&in);
2183  return NULL;
2184  }
2185  av_frame_copy_props(out, in);
2186  }
2187 
2188  td.in = in;
2189  td.out = out;
2190  ff_filter_execute(ctx, lut1d->interp, &td, NULL,
2191  FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
2192 
2193  if (out != in)
2194  av_frame_free(&in);
2195 
2196  return out;
2197 }
2198 
2199 static int filter_frame_1d(AVFilterLink *inlink, AVFrame *in)
2200 {
2201  AVFilterLink *outlink = inlink->dst->outputs[0];
2202  AVFrame *out = apply_1d_lut(inlink, in);
2203  if (!out)
2204  return AVERROR(ENOMEM);
2205  return ff_filter_frame(outlink, out);
2206 }
2207 
2208 static int lut1d_process_command(AVFilterContext *ctx, const char *cmd, const char *args,
2209  char *res, int res_len, int flags)
2210 {
2211  LUT1DContext *lut1d = ctx->priv;
2212  int ret;
2213 
2214  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
2215  if (ret < 0)
2216  return ret;
2217 
2218  ret = lut1d_init(ctx);
2219  if (ret < 0) {
2220  set_identity_matrix_1d(lut1d, 32);
2221  return ret;
2222  }
2223  return config_input_1d(ctx->inputs[0]);
2224 }
2225 
2226 static const AVFilterPad lut1d_inputs[] = {
2227  {
2228  .name = "default",
2229  .type = AVMEDIA_TYPE_VIDEO,
2230  .filter_frame = filter_frame_1d,
2231  .config_props = config_input_1d,
2232  },
2233 };
2234 
2235 const AVFilter ff_vf_lut1d = {
2236  .name = "lut1d",
2237  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a 1D LUT."),
2238  .priv_size = sizeof(LUT1DContext),
2239  .init = lut1d_init,
2240  FILTER_INPUTS(lut1d_inputs),
2243  .priv_class = &lut1d_class,
2245  .process_command = lut1d_process_command,
2246 };
2247 #endif
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:116
COMMON_OPTIONS
#define COMMON_OPTIONS
Definition: vf_lut3d.c:50
AV_PIX_FMT_GBRAP16
#define AV_PIX_FMT_GBRAP16
Definition: pixfmt.h:525
DEFINE_INTERP_FUNC_PLANAR_FLOAT
#define DEFINE_INTERP_FUNC_PLANAR_FLOAT(name, depth)
Definition: vf_lut3d.c:419
MAX_LINE_SIZE
#define MAX_LINE_SIZE
Definition: vf_lut3d.c:547
lerpf
static float lerpf(float v0, float v1, float f)
Definition: vf_lut3d.c:83
ff_framesync_configure
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
Definition: framesync.c:137
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:215
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
level
uint8_t level
Definition: svq3.c:205
mix
static int mix(int c0, int c1)
Definition: 4xm.c:716
r
const char * r
Definition: vf_curves.c:127
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
parse_m3d
static int parse_m3d(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:768
FILTER_PIXFMTS_ARRAY
#define FILTER_PIXFMTS_ARRAY(array)
Definition: filters.h:242
ff_framesync_uninit
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition: framesync.c:301
out
FILE * out
Definition: movenc.c:55
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:1061
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:764
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3170
apply_prelut
static struct rgbvec apply_prelut(const Lut3DPreLut *prelut, const struct rgbvec *s)
Definition: vf_lut3d.c:307
lerp
static struct rgbvec lerp(const struct rgbvec *v0, const struct rgbvec *v1, float f)
Definition: vf_lut3d.c:88
parse_dat
static int parse_dat(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:640
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:207
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:218
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:163
AVFILTER_DEFINE_CLASS_EXT
#define AVFILTER_DEFINE_CLASS_EXT(name, desc, options)
Definition: filters.h:265
LUT3DContext::scale
struct rgbvec scale
Definition: lut3d.h:61
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: filters.h:262
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:403
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:429
skip_line
static int skip_line(const char *p)
Definition: vf_lut3d.c:549
b
#define b
Definition: input.c:41
lut3d.h
data
const char data[16]
Definition: mxf.c:149
linear
static int linear(InterplayACMContext *s, unsigned ind, unsigned col)
Definition: interplayacm.c:135
float.h
interp_tetrahedral
static struct rgbvec interp_tetrahedral(const LUT3DContext *lut3d, const struct rgbvec *s)
Tetrahedral interpolation.
Definition: vf_lut3d.c:238
AV_PIX_FMT_BGR24
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:76
AV_PIX_FMT_BGRA
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:102
preinit
static av_cold int preinit(AVFilterContext *ctx)
Definition: af_aresample.c:48
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:189
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:205
c1
static const uint64_t c1
Definition: murmur3.c:52
FFFrameSync
Frame sync structure.
Definition: framesync.h:168
ThreadData::out
AVFrame * out
Definition: af_adeclick.c:526
PRELUT_SIZE
#define PRELUT_SIZE
Definition: lut3d.h:46
parse_cube
static int parse_cube(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:675
intfloat.h
video.h
ThreadData::in
AVFrame * in
Definition: af_adecorrelate.c:155
ff_vf_lut3d
const AVFilter ff_vf_lut3d
INTERPOLATE_PYRAMID
@ INTERPOLATE_PYRAMID
Definition: lut3d.h:34
MANTISSA_MASK
#define MANTISSA_MASK
Definition: vf_lut3d.c:60
SIGN_MASK
#define SIGN_MASK
Definition: vf_lut3d.c:61
LUT3DContext
Definition: lut3d.h:56
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:30
Lut3DPreLut::lut
float * lut[3]
Definition: lut3d.h:53
av_pix_fmt_count_planes
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3210
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:520
apply_lut
static void apply_lut(const uint16_t *lut, uint16_t *dst, int dsize)
Definition: exr.c:290
AV_PIX_FMT_GBRAP
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
Definition: pixfmt.h:212
cosf
#define cosf(x)
Definition: libm.h:78
interp
interp
Definition: vf_curves.c:62
AV_PIX_FMT_GBRP10
#define AV_PIX_FMT_GBRP10
Definition: pixfmt.h:518
val
static double val(void *priv, double ch)
Definition: aeval.c:77
a2
static double a2(void *priv, double x, double y)
Definition: vf_xfade.c:2030
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:113
AVFilterPad
A filter pad used for either input or output.
Definition: filters.h:38
pix_fmts
static enum AVPixelFormat pix_fmts[]
Definition: vf_lut3d.c:1097
SET_COLOR
#define SET_COLOR(id)
avassert.h
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:209
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
ff_video_default_filterpad
const AVFilterPad ff_video_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_VIDEO.
Definition: video.c:37
INTERPOLATE_TRILINEAR
@ INTERPOLATE_TRILINEAR
Definition: lut3d.h:32
AV_PIX_FMT_GBRAP10
#define AV_PIX_FMT_GBRAP10
Definition: pixfmt.h:522
float
float
Definition: af_crystalizer.c:122
OFFSET
#define OFFSET(x)
Definition: vf_lut3d.c:47
s
#define s(width, name)
Definition: cbs_vp9.c:198
AV_PIX_FMT_GBRAP12
#define AV_PIX_FMT_GBRAP12
Definition: pixfmt.h:523
g
const char * g
Definition: vf_curves.c:128
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:40
filters.h
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:230
ctx
AVFormatContext * ctx
Definition: movenc.c:49
fget_next_word
static char * fget_next_word(char *dst, int max, FILE *f)
Definition: vf_lut3d.c:556
DEFINE_INTERP_FUNC
#define DEFINE_INTERP_FUNC(name, nbits)
Definition: vf_lut3d.c:486
Lut3DPreLut::size
int size
Definition: lut3d.h:49
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: filters.h:263
file_open.h
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:100
AV_PIX_FMT_GBRP16
#define AV_PIX_FMT_GBRP16
Definition: pixfmt.h:521
AV_PIX_FMT_RGBA64
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:492
av_sscanf
int av_sscanf(const char *string, const char *format,...)
See libc sscanf manual for more information.
Definition: avsscanf.c:961
prelut_interp_1d_linear
static float prelut_interp_1d_linear(const Lut3DPreLut *prelut, int idx, const float s)
Definition: vf_lut3d.c:293
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:75
rgbvec::r
float r
Definition: lut3d.h:40
AV_PIX_FMT_BGR48
#define AV_PIX_FMT_BGR48
Definition: pixfmt.h:493
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:726
config_input
static int config_input(AVFilterLink *inlink)
Definition: af_acontrast.c:121
a3
static double a3(void *priv, double x, double y)
Definition: vf_xfade.c:2031
fs
#define fs(width, name, subs,...)
Definition: cbs_vp9.c:200
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:348
AV_PIX_FMT_BGR0
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:265
av_intfloat32
Definition: intfloat.h:27
filter_frame
static int filter_frame(DBEDecodeContext *s, AVFrame *frame)
Definition: dolby_e.c:1059
av_clipf
av_clipf
Definition: af_crystalizer.c:122
ff_lut3d_init_x86
void ff_lut3d_init_x86(LUT3DContext *s, const AVPixFmtDescriptor *desc)
Definition: vf_lut3d_init.c:58
AV_PIX_FMT_GBRP9
#define AV_PIX_FMT_GBRP9
Definition: pixfmt.h:517
AVFILTER_DEFINE_CLASS
#define AVFILTER_DEFINE_CLASS(fname)
Definition: filters.h:273
AV_PIX_FMT_ABGR
@ AV_PIX_FMT_ABGR
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
Definition: pixfmt.h:101
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
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:368
AV_PIX_FMT_RGB24
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:75
ff_framesync_init_dualinput
int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent)
Initialize a frame sync structure for dualinput.
Definition: framesync.c:372
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:94
master
const char * master
Definition: vf_curves.c:130
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:3135
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:83
process_command
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: af_acrusher.c:307
config_output
static int config_output(AVFilterLink *outlink)
Definition: af_aap.c:190
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:122
AV_PIX_FMT_GBRPF32
#define AV_PIX_FMT_GBRPF32
Definition: pixfmt.h:532
INTERPOLATE_PRISM
@ INTERPOLATE_PRISM
Definition: lut3d.h:35
AV_PIX_FMT_RGB48
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:488
size
int size
Definition: twinvq_data.h:10344
Lut3DPreLut::min
float min[3]
Definition: lut3d.h:50
INTERPOLATE_NEAREST
@ INTERPOLATE_NEAREST
Definition: lut3d.h:31
av_frame_is_writable
int av_frame_is_writable(AVFrame *frame)
Check if the frame data is writable.
Definition: frame.c:662
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:900
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:59
a0
static double a0(void *priv, double x, double y)
Definition: vf_xfade.c:2028
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:263
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:97
av_frame_side_data_remove_by_props
void av_frame_side_data_remove_by_props(AVFrameSideData ***sd, int *nb_sd, int props)
Remove and free all side data instances that match any of the given side data properties.
Definition: frame.c:964
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:389
M_PI
#define M_PI
Definition: mathematics.h:67
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:220
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:182
AV_PIX_FMT_ARGB
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition: pixfmt.h:99
uninit
static void uninit(AVBSFContext *ctx)
Definition: pcm_rechunk.c:68
AV_PIX_FMT_BGRA64
#define AV_PIX_FMT_BGRA64
Definition: pixfmt.h:497
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
LUT3DContext::interp
avfilter_action_func * interp
Definition: lut3d.h:66
tetrahedral
static av_always_inline v3u16_t tetrahedral(const SwsLut3D *lut3d, int Rx, int Gx, int Bx, int Rf, int Gf, int Bf)
Definition: lut3d.c:81
DEFINE_INTERP_FUNC_PLANAR
#define DEFINE_INTERP_FUNC_PLANAR(name, nbits, depth)
Definition: vf_lut3d.c:321
AV_PIX_FMT_GBRP12
#define AV_PIX_FMT_GBRP12
Definition: pixfmt.h:519
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:31
ff_filter_get_nb_threads
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:840
ThreadData
Used for passing data between threads.
Definition: dsddec.c:71
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
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:139
AVFilterPad::name
const char * name
Pad name.
Definition: filters.h:44
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:161
AV_SIDE_DATA_PROP_COLOR_DEPENDENT
@ AV_SIDE_DATA_PROP_COLOR_DEPENDENT
Side data depends on the video color space.
Definition: frame.h:299
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:201
sanitizef
static float sanitizef(float f)
Definition: vf_lut3d.c:63
ret
ret
Definition: filter_design.txt:187
AV_PIX_FMT_0BGR
@ AV_PIX_FMT_0BGR
packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined
Definition: pixfmt.h:264
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:605
NEXT_LINE_OR_GOTO
#define NEXT_LINE_OR_GOTO(loop_cond, label)
Definition: vf_lut3d.c:597
rgbvec::g
float g
Definition: lut3d.h:40
ff_vf_haldclut
const AVFilter ff_vf_haldclut
NEXT
#define NEXT(x)
Definition: vf_lut3d.c:98
LUT3DContext::prelut
Lut3DPreLut prelut
Definition: lut3d.h:67
c2
static const uint64_t c2
Definition: murmur3.c:53
ff_filter_execute
int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
Definition: avfilter.c:1666
rgbvec::b
float b
Definition: lut3d.h:40
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition: opt.h:259
AV_PIX_FMT_GBRAPF32
#define AV_PIX_FMT_GBRAPF32
Definition: pixfmt.h:533
interp_nearest
static struct rgbvec interp_nearest(const LUT3DContext *lut3d, const struct rgbvec *s)
Get the nearest defined point.
Definition: vf_lut3d.c:103
LUT3DContext::step
int step
Definition: lut3d.h:65
AV_PIX_FMT_FLAG_PLANAR
#define AV_PIX_FMT_FLAG_PLANAR
At least one pixel component is not in the first data plane.
Definition: pixdesc.h:132
TFLAGS
#define TFLAGS
Definition: vf_lut3d.c:49
AVFilterContext
An instance of a filter.
Definition: avfilter.h:457
NEXT_LINE
#define NEXT_LINE(loop_cond)
Definition: vf_lut3d.c:590
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:165
AVFILTER_FLAG_SLICE_THREADS
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:152
desc
const char * desc
Definition: libsvtav1.c:79
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
mem.h
FLAGS
#define FLAGS
Definition: vf_lut3d.c:48
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
scale
static void scale(int *out, const int *in, const int w, const int h, const int shift)
Definition: intra.c:291
NEAR
#define NEAR(x)
Definition: vf_lut3d.c:96
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:79
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:190
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:482
AV_PIX_FMT_0RGB
@ AV_PIX_FMT_0RGB
packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined
Definition: pixfmt.h:262
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
INTERPOLATE_TETRAHEDRAL
@ INTERPOLATE_TETRAHEDRAL
Definition: lut3d.h:33
a1
static double a1(void *priv, double x, double y)
Definition: vf_xfade.c:2029
h
h
Definition: vp9dsp_template.c:2070
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:352
ff_vf_lut1d
const AVFilter ff_vf_lut1d
avstring.h
ff_framesync_dualinput_get
int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1)
Definition: framesync.c:390
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition: opt.h:276
drawutils.h
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition: opt.h:299
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