FFmpeg
vf_lut3d.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Clément Bœsch
3  * Copyright (c) 2018 Paul B Mahol
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /**
23  * @file
24  * 3D Lookup table filter
25  */
26 
27 #include <float.h>
28 
29 #include "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 "internal.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)
385 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 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)
391 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 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)
397 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 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)
403 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 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)
409 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 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)
415 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 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)
482 DEFINE_INTERP_FUNC_PLANAR_FLOAT(tetrahedral, 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)
537 DEFINE_INTERP_FUNC(tetrahedral, 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)
543 DEFINE_INTERP_FUNC(tetrahedral, 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  av_sscanf(line + 11, "%f %f %f", vals, vals + 1, vals + 2);
707  av_log(ctx, AV_LOG_DEBUG, "min: %f %f %f | max: %f %f %f\n",
708  min[0], min[1], min[2], max[0], max[1], max[2]);
709  goto try_again;
710  } else if (!strncmp(line, "TITLE", 5)) {
711  goto try_again;
712  }
713  } while (skip_line(line));
714  if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3)
715  return AVERROR_INVALIDDATA;
716  }
717  }
718  }
719  break;
720  }
721  }
722 
723  lut3d->scale.r = av_clipf(1. / (max[0] - min[0]), 0.f, 1.f);
724  lut3d->scale.g = av_clipf(1. / (max[1] - min[1]), 0.f, 1.f);
725  lut3d->scale.b = av_clipf(1. / (max[2] - min[2]), 0.f, 1.f);
726 
727  return 0;
728 }
729 
730 /* Assume 17x17x17 LUT with a 16-bit depth
731  * FIXME: it seems there are various 3dl formats */
732 static int parse_3dl(AVFilterContext *ctx, FILE *f)
733 {
734  char line[MAX_LINE_SIZE];
735  LUT3DContext *lut3d = ctx->priv;
736  int ret, i, j, k;
737  const int size = 17;
738  const int size2 = 17 * 17;
739  const float scale = 16*16*16;
740 
741  lut3d->lutsize = size;
742 
743  ret = allocate_3dlut(ctx, size, 0);
744  if (ret < 0)
745  return ret;
746 
748  for (k = 0; k < size; k++) {
749  for (j = 0; j < size; j++) {
750  for (i = 0; i < size; i++) {
751  int r, g, b;
752  struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i];
753 
755  if (av_sscanf(line, "%d %d %d", &r, &g, &b) != 3)
756  return AVERROR_INVALIDDATA;
757  vec->r = r / scale;
758  vec->g = g / scale;
759  vec->b = b / scale;
760  }
761  }
762  }
763  return 0;
764 }
765 
766 /* Pandora format */
767 static int parse_m3d(AVFilterContext *ctx, FILE *f)
768 {
769  LUT3DContext *lut3d = ctx->priv;
770  float scale;
771  int ret, i, j, k, size, size2, in = -1, out = -1;
772  char line[MAX_LINE_SIZE];
773  uint8_t rgb_map[3] = {0, 1, 2};
774 
775  while (fgets(line, sizeof(line), f)) {
776  if (!strncmp(line, "in", 2)) in = strtol(line + 2, NULL, 0);
777  else if (!strncmp(line, "out", 3)) out = strtol(line + 3, NULL, 0);
778  else if (!strncmp(line, "values", 6)) {
779  const char *p = line + 6;
780 #define SET_COLOR(id) do { \
781  while (av_isspace(*p)) \
782  p++; \
783  switch (*p) { \
784  case 'r': rgb_map[id] = 0; break; \
785  case 'g': rgb_map[id] = 1; break; \
786  case 'b': rgb_map[id] = 2; break; \
787  } \
788  while (*p && !av_isspace(*p)) \
789  p++; \
790 } while (0)
791  SET_COLOR(0);
792  SET_COLOR(1);
793  SET_COLOR(2);
794  break;
795  }
796  }
797 
798  if (in == -1 || out == -1) {
799  av_log(ctx, AV_LOG_ERROR, "in and out must be defined\n");
800  return AVERROR_INVALIDDATA;
801  }
802  if (in < 2 || out < 2 ||
805  av_log(ctx, AV_LOG_ERROR, "invalid in (%d) or out (%d)\n", in, out);
806  return AVERROR_INVALIDDATA;
807  }
808  for (size = 1; size*size*size < in; size++);
809  lut3d->lutsize = size;
810  size2 = size * size;
811 
812  ret = allocate_3dlut(ctx, size, 0);
813  if (ret < 0)
814  return ret;
815 
816  scale = 1. / (out - 1);
817 
818  for (k = 0; k < size; k++) {
819  for (j = 0; j < size; j++) {
820  for (i = 0; i < size; i++) {
821  struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i];
822  float val[3];
823 
824  NEXT_LINE(0);
825  if (av_sscanf(line, "%f %f %f", val, val + 1, val + 2) != 3)
826  return AVERROR_INVALIDDATA;
827  vec->r = val[rgb_map[0]] * scale;
828  vec->g = val[rgb_map[1]] * scale;
829  vec->b = val[rgb_map[2]] * scale;
830  }
831  }
832  }
833  return 0;
834 }
835 
836 static int nearest_sample_index(float *data, float x, int low, int hi)
837 {
838  int mid;
839  if (x < data[low])
840  return low;
841 
842  if (x > data[hi])
843  return hi;
844 
845  for (;;) {
846  av_assert0(x >= data[low]);
847  av_assert0(x <= data[hi]);
848  av_assert0((hi-low) > 0);
849 
850  if (hi - low == 1)
851  return low;
852 
853  mid = (low + hi) / 2;
854 
855  if (x < data[mid])
856  hi = mid;
857  else
858  low = mid;
859  }
860 
861  return 0;
862 }
863 
864 #define NEXT_FLOAT_OR_GOTO(value, label) \
865  if (!fget_next_word(line, sizeof(line) ,f)) { \
866  ret = AVERROR_INVALIDDATA; \
867  goto label; \
868  } \
869  if (av_sscanf(line, "%f", &value) != 1) { \
870  ret = AVERROR_INVALIDDATA; \
871  goto label; \
872  }
873 
875 {
876  LUT3DContext *lut3d = ctx->priv;
877  char line[MAX_LINE_SIZE];
878  float in_min[3] = {0.0, 0.0, 0.0};
879  float in_max[3] = {1.0, 1.0, 1.0};
880  float out_min[3] = {0.0, 0.0, 0.0};
881  float out_max[3] = {1.0, 1.0, 1.0};
882  int inside_metadata = 0, size, size2;
883  int prelut = 0;
884  int ret = 0;
885 
886  int prelut_sizes[3] = {0, 0, 0};
887  float *in_prelut[3] = {NULL, NULL, NULL};
888  float *out_prelut[3] = {NULL, NULL, NULL};
889 
891  if (strncmp(line, "CSPLUTV100", 10)) {
892  av_log(ctx, AV_LOG_ERROR, "Not cineSpace LUT format\n");
893  ret = AVERROR(EINVAL);
894  goto end;
895  }
896 
898  if (strncmp(line, "3D", 2)) {
899  av_log(ctx, AV_LOG_ERROR, "Not 3D LUT format\n");
900  ret = AVERROR(EINVAL);
901  goto end;
902  }
903 
904  while (1) {
906 
907  if (!strncmp(line, "BEGIN METADATA", 14)) {
908  inside_metadata = 1;
909  continue;
910  }
911  if (!strncmp(line, "END METADATA", 12)) {
912  inside_metadata = 0;
913  continue;
914  }
915  if (inside_metadata == 0) {
916  int size_r, size_g, size_b;
917 
918  for (int i = 0; i < 3; i++) {
919  int npoints = strtol(line, NULL, 0);
920 
921  if (npoints > 2) {
922  float v,last;
923 
924  if (npoints > PRELUT_SIZE) {
925  av_log(ctx, AV_LOG_ERROR, "Prelut size too large.\n");
927  goto end;
928  }
929 
930  if (in_prelut[i] || out_prelut[i]) {
931  av_log(ctx, AV_LOG_ERROR, "Invalid file has multiple preluts.\n");
933  goto end;
934  }
935 
936  in_prelut[i] = (float*)av_malloc(npoints * sizeof(float));
937  out_prelut[i] = (float*)av_malloc(npoints * sizeof(float));
938  if (!in_prelut[i] || !out_prelut[i]) {
939  ret = AVERROR(ENOMEM);
940  goto end;
941  }
942 
943  prelut_sizes[i] = npoints;
944  in_min[i] = FLT_MAX;
945  in_max[i] = -FLT_MAX;
946  out_min[i] = FLT_MAX;
947  out_max[i] = -FLT_MAX;
948 
949  for (int j = 0; j < npoints; j++) {
950  NEXT_FLOAT_OR_GOTO(v, end)
951  in_min[i] = FFMIN(in_min[i], v);
952  in_max[i] = FFMAX(in_max[i], v);
953  in_prelut[i][j] = v;
954  if (j > 0 && v < last) {
955  av_log(ctx, AV_LOG_ERROR, "Invalid file, non increasing prelut.\n");
956  ret = AVERROR(ENOMEM);
957  goto end;
958  }
959  last = v;
960  }
961 
962  for (int j = 0; j < npoints; j++) {
963  NEXT_FLOAT_OR_GOTO(v, end)
964  out_min[i] = FFMIN(out_min[i], v);
965  out_max[i] = FFMAX(out_max[i], v);
966  out_prelut[i][j] = v;
967  }
968 
969  } else if (npoints == 2) {
971  if (av_sscanf(line, "%f %f", &in_min[i], &in_max[i]) != 2) {
973  goto end;
974  }
976  if (av_sscanf(line, "%f %f", &out_min[i], &out_max[i]) != 2) {
978  goto end;
979  }
980 
981  } else {
982  av_log(ctx, AV_LOG_ERROR, "Unsupported number of pre-lut points.\n");
984  goto end;
985  }
986 
988  }
989 
990  if (av_sscanf(line, "%d %d %d", &size_r, &size_g, &size_b) != 3) {
991  ret = AVERROR(EINVAL);
992  goto end;
993  }
994  if (size_r != size_g || size_r != size_b) {
995  av_log(ctx, AV_LOG_ERROR, "Unsupported size combination: %dx%dx%d.\n", size_r, size_g, size_b);
997  goto end;
998  }
999 
1000  size = size_r;
1001  size2 = size * size;
1002 
1003  if (prelut_sizes[0] && prelut_sizes[1] && prelut_sizes[2])
1004  prelut = 1;
1005 
1006  ret = allocate_3dlut(ctx, size, prelut);
1007  if (ret < 0)
1008  return ret;
1009 
1010  for (int k = 0; k < size; k++) {
1011  for (int j = 0; j < size; j++) {
1012  for (int i = 0; i < size; i++) {
1013  struct rgbvec *vec = &lut3d->lut[i * size2 + j * size + k];
1014 
1016  if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3) {
1018  goto end;
1019  }
1020 
1021  vec->r *= out_max[0] - out_min[0];
1022  vec->g *= out_max[1] - out_min[1];
1023  vec->b *= out_max[2] - out_min[2];
1024  }
1025  }
1026  }
1027 
1028  break;
1029  }
1030  }
1031 
1032  if (prelut) {
1033  for (int c = 0; c < 3; c++) {
1034 
1035  lut3d->prelut.min[c] = in_min[c];
1036  lut3d->prelut.max[c] = in_max[c];
1037  lut3d->prelut.scale[c] = (1.0f / (float)(in_max[c] - in_min[c])) * (lut3d->prelut.size - 1);
1038 
1039  for (int i = 0; i < lut3d->prelut.size; ++i) {
1040  float mix = (float) i / (float)(lut3d->prelut.size - 1);
1041  float x = lerpf(in_min[c], in_max[c], mix), a, b;
1042 
1043  int idx = nearest_sample_index(in_prelut[c], x, 0, prelut_sizes[c]-1);
1044  av_assert0(idx + 1 < prelut_sizes[c]);
1045 
1046  a = out_prelut[c][idx + 0];
1047  b = out_prelut[c][idx + 1];
1048  mix = x - in_prelut[c][idx];
1049 
1050  lut3d->prelut.lut[c][i] = sanitizef(lerpf(a, b, mix));
1051  }
1052  }
1053  lut3d->scale.r = 1.00f;
1054  lut3d->scale.g = 1.00f;
1055  lut3d->scale.b = 1.00f;
1056 
1057  } else {
1058  lut3d->scale.r = av_clipf(1. / (in_max[0] - in_min[0]), 0.f, 1.f);
1059  lut3d->scale.g = av_clipf(1. / (in_max[1] - in_min[1]), 0.f, 1.f);
1060  lut3d->scale.b = av_clipf(1. / (in_max[2] - in_min[2]), 0.f, 1.f);
1061  }
1062 
1063 end:
1064  for (int c = 0; c < 3; c++) {
1065  av_freep(&in_prelut[c]);
1066  av_freep(&out_prelut[c]);
1067  }
1068  return ret;
1069 }
1070 
1072 {
1073  LUT3DContext *lut3d = ctx->priv;
1074  int ret, i, j, k;
1075  const int size2 = size * size;
1076  const float c = 1. / (size - 1);
1077 
1078  ret = allocate_3dlut(ctx, size, 0);
1079  if (ret < 0)
1080  return ret;
1081 
1082  for (k = 0; k < size; k++) {
1083  for (j = 0; j < size; j++) {
1084  for (i = 0; i < size; i++) {
1085  struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i];
1086  vec->r = k * c;
1087  vec->g = j * c;
1088  vec->b = i * c;
1089  }
1090  }
1091  }
1092 
1093  return 0;
1094 }
1095 
1096 static const enum AVPixelFormat pix_fmts[] = {
1112 };
1113 
1115 {
1116  int depth, is16bit, isfloat, planar;
1117  LUT3DContext *lut3d = inlink->dst->priv;
1119 
1120  depth = desc->comp[0].depth;
1121  is16bit = desc->comp[0].depth > 8;
1122  planar = desc->flags & AV_PIX_FMT_FLAG_PLANAR;
1123  isfloat = desc->flags & AV_PIX_FMT_FLAG_FLOAT;
1124  ff_fill_rgba_map(lut3d->rgba_map, inlink->format);
1125  lut3d->step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit);
1126 
1127 #define SET_FUNC(name) do { \
1128  if (planar && !isfloat) { \
1129  switch (depth) { \
1130  case 8: lut3d->interp = interp_8_##name##_p8; break; \
1131  case 9: lut3d->interp = interp_16_##name##_p9; break; \
1132  case 10: lut3d->interp = interp_16_##name##_p10; break; \
1133  case 12: lut3d->interp = interp_16_##name##_p12; break; \
1134  case 14: lut3d->interp = interp_16_##name##_p14; break; \
1135  case 16: lut3d->interp = interp_16_##name##_p16; break; \
1136  } \
1137  } else if (isfloat) { lut3d->interp = interp_##name##_pf32; \
1138  } else if (is16bit) { lut3d->interp = interp_16_##name; \
1139  } else { lut3d->interp = interp_8_##name; } \
1140 } while (0)
1141 
1142  switch (lut3d->interpolation) {
1143  case INTERPOLATE_NEAREST: SET_FUNC(nearest); break;
1144  case INTERPOLATE_TRILINEAR: SET_FUNC(trilinear); break;
1145  case INTERPOLATE_TETRAHEDRAL: SET_FUNC(tetrahedral); break;
1146  case INTERPOLATE_PYRAMID: SET_FUNC(pyramid); break;
1147  case INTERPOLATE_PRISM: SET_FUNC(prism); break;
1148  default:
1149  av_assert0(0);
1150  }
1151 
1152 #if ARCH_X86
1153  ff_lut3d_init_x86(lut3d, desc);
1154 #endif
1155 
1156  return 0;
1157 }
1158 
1160 {
1161  AVFilterContext *ctx = inlink->dst;
1162  LUT3DContext *lut3d = ctx->priv;
1163  AVFilterLink *outlink = inlink->dst->outputs[0];
1164  AVFrame *out;
1165  ThreadData td;
1166 
1167  if (av_frame_is_writable(in)) {
1168  out = in;
1169  } else {
1170  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
1171  if (!out) {
1172  av_frame_free(&in);
1173  return NULL;
1174  }
1175  av_frame_copy_props(out, in);
1176  }
1177 
1178  td.in = in;
1179  td.out = out;
1180  ff_filter_execute(ctx, lut3d->interp, &td, NULL,
1181  FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
1182 
1183  if (out != in)
1184  av_frame_free(&in);
1185 
1186  return out;
1187 }
1188 
1190 {
1191  AVFilterLink *outlink = inlink->dst->outputs[0];
1192  AVFrame *out = apply_lut(inlink, in);
1193  if (!out)
1194  return AVERROR(ENOMEM);
1195  return ff_filter_frame(outlink, out);
1196 }
1197 
1198 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
1199  char *res, int res_len, int flags)
1200 {
1201  int ret;
1202 
1203  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
1204  if (ret < 0)
1205  return ret;
1206 
1207  return config_input(ctx->inputs[0]);
1208 }
1209 
1210 #if CONFIG_LUT3D_FILTER || CONFIG_HALDCLUT_FILTER
1211 
1212 /* These options are shared between several filters;
1213  * &lut3d_haldclut_options[COMMON_OPTIONS_OFFSET] must always
1214  * point to the first of the COMMON_OPTIONS. */
1215 #define COMMON_OPTIONS_OFFSET CONFIG_LUT3D_FILTER
1216 static const AVOption lut3d_haldclut_options[] = {
1217 #if CONFIG_LUT3D_FILTER
1218  { "file", "set 3D LUT file name", OFFSET(file), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
1219 #endif
1220 #if CONFIG_HALDCLUT_FILTER
1221  { "clut", "when to process CLUT", OFFSET(clut), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, .flags = TFLAGS, .unit = "clut" },
1222  { "first", "process only first CLUT, ignore rest", 0, AV_OPT_TYPE_CONST, {.i64=0}, .flags = TFLAGS, .unit = "clut" },
1223  { "all", "process all CLUTs", 0, AV_OPT_TYPE_CONST, {.i64=1}, .flags = TFLAGS, .unit = "clut" },
1224 #endif
1226 };
1227 
1228 #if CONFIG_LUT3D_FILTER
1229 
1230 AVFILTER_DEFINE_CLASS_EXT(lut3d, "lut3d", lut3d_haldclut_options);
1231 
1232 static av_cold int lut3d_init(AVFilterContext *ctx)
1233 {
1234  int ret;
1235  FILE *f;
1236  const char *ext;
1237  LUT3DContext *lut3d = ctx->priv;
1238 
1239  lut3d->scale.r = lut3d->scale.g = lut3d->scale.b = 1.f;
1240 
1241  if (!lut3d->file) {
1242  return set_identity_matrix(ctx, 32);
1243  }
1244 
1245  f = avpriv_fopen_utf8(lut3d->file, "r");
1246  if (!f) {
1247  ret = AVERROR(errno);
1248  av_log(ctx, AV_LOG_ERROR, "%s: %s\n", lut3d->file, av_err2str(ret));
1249  return ret;
1250  }
1251 
1252  ext = strrchr(lut3d->file, '.');
1253  if (!ext) {
1254  av_log(ctx, AV_LOG_ERROR, "Unable to guess the format from the extension\n");
1256  goto end;
1257  }
1258  ext++;
1259 
1260  if (!av_strcasecmp(ext, "dat")) {
1261  ret = parse_dat(ctx, f);
1262  } else if (!av_strcasecmp(ext, "3dl")) {
1263  ret = parse_3dl(ctx, f);
1264  } else if (!av_strcasecmp(ext, "cube")) {
1265  ret = parse_cube(ctx, f);
1266  } else if (!av_strcasecmp(ext, "m3d")) {
1267  ret = parse_m3d(ctx, f);
1268  } else if (!av_strcasecmp(ext, "csp")) {
1269  ret = parse_cinespace(ctx, f);
1270  } else {
1271  av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext);
1272  ret = AVERROR(EINVAL);
1273  }
1274 
1275  if (!ret && !lut3d->lutsize) {
1276  av_log(ctx, AV_LOG_ERROR, "3D LUT is empty\n");
1278  }
1279 
1280 end:
1281  fclose(f);
1282  return ret;
1283 }
1284 
1285 static av_cold void lut3d_uninit(AVFilterContext *ctx)
1286 {
1287  LUT3DContext *lut3d = ctx->priv;
1288  int i;
1289  av_freep(&lut3d->lut);
1290 
1291  for (i = 0; i < 3; i++) {
1292  av_freep(&lut3d->prelut.lut[i]);
1293  }
1294 }
1295 
1296 static const AVFilterPad lut3d_inputs[] = {
1297  {
1298  .name = "default",
1299  .type = AVMEDIA_TYPE_VIDEO,
1300  .filter_frame = filter_frame,
1301  .config_props = config_input,
1302  },
1303 };
1304 
1305 const AVFilter ff_vf_lut3d = {
1306  .name = "lut3d",
1307  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a 3D LUT."),
1308  .priv_size = sizeof(LUT3DContext),
1309  .init = lut3d_init,
1310  .uninit = lut3d_uninit,
1311  FILTER_INPUTS(lut3d_inputs),
1314  .priv_class = &lut3d_class,
1316  .process_command = process_command,
1317 };
1318 #endif
1319 
1320 #if CONFIG_HALDCLUT_FILTER
1321 
1322 static void update_clut_packed(LUT3DContext *lut3d, const AVFrame *frame)
1323 {
1324  const uint8_t *data = frame->data[0];
1325  const ptrdiff_t linesize = frame->linesize[0];
1326  const int w = lut3d->clut_width;
1327  const int step = lut3d->clut_step;
1328  const uint8_t *rgba_map = lut3d->clut_rgba_map;
1329  const int level = lut3d->lutsize;
1330  const int level2 = lut3d->lutsize2;
1331 
1332 #define LOAD_CLUT(nbits) do { \
1333  int i, j, k, x = 0, y = 0; \
1334  \
1335  for (k = 0; k < level; k++) { \
1336  for (j = 0; j < level; j++) { \
1337  for (i = 0; i < level; i++) { \
1338  const uint##nbits##_t *src = (const uint##nbits##_t *) \
1339  (data + y*linesize + x*step); \
1340  struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k]; \
1341  vec->r = src[rgba_map[0]] / (float)((1<<(nbits)) - 1); \
1342  vec->g = src[rgba_map[1]] / (float)((1<<(nbits)) - 1); \
1343  vec->b = src[rgba_map[2]] / (float)((1<<(nbits)) - 1); \
1344  if (++x == w) { \
1345  x = 0; \
1346  y++; \
1347  } \
1348  } \
1349  } \
1350  } \
1351 } while (0)
1352 
1353  switch (lut3d->clut_bits) {
1354  case 8: LOAD_CLUT(8); break;
1355  case 16: LOAD_CLUT(16); break;
1356  }
1357 }
1358 
1359 static void update_clut_planar(LUT3DContext *lut3d, const AVFrame *frame)
1360 {
1361  const uint8_t *datag = frame->data[0];
1362  const uint8_t *datab = frame->data[1];
1363  const uint8_t *datar = frame->data[2];
1364  const ptrdiff_t glinesize = frame->linesize[0];
1365  const ptrdiff_t blinesize = frame->linesize[1];
1366  const ptrdiff_t rlinesize = frame->linesize[2];
1367  const int w = lut3d->clut_width;
1368  const int level = lut3d->lutsize;
1369  const int level2 = lut3d->lutsize2;
1370 
1371 #define LOAD_CLUT_PLANAR(nbits, depth) do { \
1372  int i, j, k, x = 0, y = 0; \
1373  \
1374  for (k = 0; k < level; k++) { \
1375  for (j = 0; j < level; j++) { \
1376  for (i = 0; i < level; i++) { \
1377  const uint##nbits##_t *gsrc = (const uint##nbits##_t *) \
1378  (datag + y*glinesize); \
1379  const uint##nbits##_t *bsrc = (const uint##nbits##_t *) \
1380  (datab + y*blinesize); \
1381  const uint##nbits##_t *rsrc = (const uint##nbits##_t *) \
1382  (datar + y*rlinesize); \
1383  struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k]; \
1384  vec->r = gsrc[x] / (float)((1<<(depth)) - 1); \
1385  vec->g = bsrc[x] / (float)((1<<(depth)) - 1); \
1386  vec->b = rsrc[x] / (float)((1<<(depth)) - 1); \
1387  if (++x == w) { \
1388  x = 0; \
1389  y++; \
1390  } \
1391  } \
1392  } \
1393  } \
1394 } while (0)
1395 
1396  switch (lut3d->clut_bits) {
1397  case 8: LOAD_CLUT_PLANAR(8, 8); break;
1398  case 9: LOAD_CLUT_PLANAR(16, 9); break;
1399  case 10: LOAD_CLUT_PLANAR(16, 10); break;
1400  case 12: LOAD_CLUT_PLANAR(16, 12); break;
1401  case 14: LOAD_CLUT_PLANAR(16, 14); break;
1402  case 16: LOAD_CLUT_PLANAR(16, 16); break;
1403  }
1404 }
1405 
1406 static void update_clut_float(LUT3DContext *lut3d, const AVFrame *frame)
1407 {
1408  const uint8_t *datag = frame->data[0];
1409  const uint8_t *datab = frame->data[1];
1410  const uint8_t *datar = frame->data[2];
1411  const ptrdiff_t glinesize = frame->linesize[0];
1412  const ptrdiff_t blinesize = frame->linesize[1];
1413  const ptrdiff_t rlinesize = frame->linesize[2];
1414  const int w = lut3d->clut_width;
1415  const int level = lut3d->lutsize;
1416  const int level2 = lut3d->lutsize2;
1417 
1418  int i, j, k, x = 0, y = 0;
1419 
1420  for (k = 0; k < level; k++) {
1421  for (j = 0; j < level; j++) {
1422  for (i = 0; i < level; i++) {
1423  const float *gsrc = (const float *)(datag + y*glinesize);
1424  const float *bsrc = (const float *)(datab + y*blinesize);
1425  const float *rsrc = (const float *)(datar + y*rlinesize);
1426  struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k];
1427  vec->r = rsrc[x];
1428  vec->g = gsrc[x];
1429  vec->b = bsrc[x];
1430  if (++x == w) {
1431  x = 0;
1432  y++;
1433  }
1434  }
1435  }
1436  }
1437 }
1438 
1439 static int config_output(AVFilterLink *outlink)
1440 {
1441  AVFilterContext *ctx = outlink->src;
1442  LUT3DContext *lut3d = ctx->priv;
1443  int ret;
1444 
1445  ret = ff_framesync_init_dualinput(&lut3d->fs, ctx);
1446  if (ret < 0)
1447  return ret;
1448  outlink->w = ctx->inputs[0]->w;
1449  outlink->h = ctx->inputs[0]->h;
1450  outlink->time_base = ctx->inputs[0]->time_base;
1451  if ((ret = ff_framesync_configure(&lut3d->fs)) < 0)
1452  return ret;
1453  return 0;
1454 }
1455 
1456 static int activate(AVFilterContext *ctx)
1457 {
1458  LUT3DContext *s = ctx->priv;
1459  return ff_framesync_activate(&s->fs);
1460 }
1461 
1462 static int config_clut(AVFilterLink *inlink)
1463 {
1464  int size, level, w, h;
1465  AVFilterContext *ctx = inlink->dst;
1466  LUT3DContext *lut3d = ctx->priv;
1468 
1469  av_assert0(desc);
1470 
1471  lut3d->clut_bits = desc->comp[0].depth;
1472  lut3d->clut_planar = av_pix_fmt_count_planes(inlink->format) > 1;
1473  lut3d->clut_float = desc->flags & AV_PIX_FMT_FLAG_FLOAT;
1474 
1475  lut3d->clut_step = av_get_padded_bits_per_pixel(desc) >> 3;
1476  ff_fill_rgba_map(lut3d->clut_rgba_map, inlink->format);
1477 
1478  if (inlink->w > inlink->h)
1479  av_log(ctx, AV_LOG_INFO, "Padding on the right (%dpx) of the "
1480  "Hald CLUT will be ignored\n", inlink->w - inlink->h);
1481  else if (inlink->w < inlink->h)
1482  av_log(ctx, AV_LOG_INFO, "Padding at the bottom (%dpx) of the "
1483  "Hald CLUT will be ignored\n", inlink->h - inlink->w);
1484  lut3d->clut_width = w = h = FFMIN(inlink->w, inlink->h);
1485 
1486  for (level = 1; level*level*level < w; level++);
1487  size = level*level*level;
1488  if (size != w) {
1489  av_log(ctx, AV_LOG_WARNING, "The Hald CLUT width does not match the level\n");
1490  return AVERROR_INVALIDDATA;
1491  }
1492  av_assert0(w == h && w == size);
1493  level *= level;
1494  if (level > MAX_LEVEL) {
1495  const int max_clut_level = sqrt(MAX_LEVEL);
1496  const int max_clut_size = max_clut_level*max_clut_level*max_clut_level;
1497  av_log(ctx, AV_LOG_ERROR, "Too large Hald CLUT "
1498  "(maximum level is %d, or %dx%d CLUT)\n",
1499  max_clut_level, max_clut_size, max_clut_size);
1500  return AVERROR(EINVAL);
1501  }
1502 
1503  return allocate_3dlut(ctx, level, 0);
1504 }
1505 
1506 static int update_apply_clut(FFFrameSync *fs)
1507 {
1508  AVFilterContext *ctx = fs->parent;
1509  LUT3DContext *lut3d = ctx->priv;
1510  AVFilterLink *inlink = ctx->inputs[0];
1511  AVFrame *master, *second, *out;
1512  int ret;
1513 
1514  ret = ff_framesync_dualinput_get(fs, &master, &second);
1515  if (ret < 0)
1516  return ret;
1517  if (!second)
1518  return ff_filter_frame(ctx->outputs[0], master);
1519  if (lut3d->clut || !lut3d->got_clut) {
1520  if (lut3d->clut_float)
1521  update_clut_float(ctx->priv, second);
1522  else if (lut3d->clut_planar)
1523  update_clut_planar(ctx->priv, second);
1524  else
1525  update_clut_packed(ctx->priv, second);
1526  lut3d->got_clut = 1;
1527  }
1528  out = apply_lut(inlink, master);
1529  return ff_filter_frame(ctx->outputs[0], out);
1530 }
1531 
1532 static av_cold int haldclut_init(AVFilterContext *ctx)
1533 {
1534  LUT3DContext *lut3d = ctx->priv;
1535  lut3d->scale.r = lut3d->scale.g = lut3d->scale.b = 1.f;
1536  lut3d->fs.on_event = update_apply_clut;
1537  return 0;
1538 }
1539 
1540 static av_cold void haldclut_uninit(AVFilterContext *ctx)
1541 {
1542  LUT3DContext *lut3d = ctx->priv;
1543  ff_framesync_uninit(&lut3d->fs);
1544  av_freep(&lut3d->lut);
1545 }
1546 
1548  &lut3d_haldclut_options[COMMON_OPTIONS_OFFSET]);
1549 
1550 static const AVFilterPad haldclut_inputs[] = {
1551  {
1552  .name = "main",
1553  .type = AVMEDIA_TYPE_VIDEO,
1554  .config_props = config_input,
1555  },{
1556  .name = "clut",
1557  .type = AVMEDIA_TYPE_VIDEO,
1558  .config_props = config_clut,
1559  },
1560 };
1561 
1562 static const AVFilterPad haldclut_outputs[] = {
1563  {
1564  .name = "default",
1565  .type = AVMEDIA_TYPE_VIDEO,
1566  .config_props = config_output,
1567  },
1568 };
1569 
1570 const AVFilter ff_vf_haldclut = {
1571  .name = "haldclut",
1572  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a Hald CLUT."),
1573  .priv_size = sizeof(LUT3DContext),
1574  .preinit = haldclut_framesync_preinit,
1575  .init = haldclut_init,
1576  .uninit = haldclut_uninit,
1577  .activate = activate,
1578  FILTER_INPUTS(haldclut_inputs),
1579  FILTER_OUTPUTS(haldclut_outputs),
1581  .priv_class = &haldclut_class,
1583  .process_command = process_command,
1584 };
1585 #endif
1586 
1587 #endif /* CONFIG_LUT3D_FILTER || CONFIG_HALDCLUT_FILTER */
1588 
1589 #if CONFIG_LUT1D_FILTER
1590 
1591 enum interp_1d_mode {
1592  INTERPOLATE_1D_NEAREST,
1593  INTERPOLATE_1D_LINEAR,
1594  INTERPOLATE_1D_CUBIC,
1595  INTERPOLATE_1D_COSINE,
1596  INTERPOLATE_1D_SPLINE,
1597  NB_INTERP_1D_MODE
1598 };
1599 
1600 #define MAX_1D_LEVEL 65536
1601 
1602 typedef struct LUT1DContext {
1603  const AVClass *class;
1604  char *file;
1605  int interpolation; ///<interp_1d_mode
1606  struct rgbvec scale;
1607  uint8_t rgba_map[4];
1608  int step;
1609  float lut[3][MAX_1D_LEVEL];
1610  int lutsize;
1612 } LUT1DContext;
1613 
1614 #undef OFFSET
1615 #define OFFSET(x) offsetof(LUT1DContext, x)
1616 
1617 static void set_identity_matrix_1d(LUT1DContext *lut1d, int size)
1618 {
1619  const float c = 1. / (size - 1);
1620  int i;
1621 
1622  lut1d->lutsize = size;
1623  for (i = 0; i < size; i++) {
1624  lut1d->lut[0][i] = i * c;
1625  lut1d->lut[1][i] = i * c;
1626  lut1d->lut[2][i] = i * c;
1627  }
1628 }
1629 
1630 static int parse_cinespace_1d(AVFilterContext *ctx, FILE *f)
1631 {
1632  LUT1DContext *lut1d = ctx->priv;
1633  char line[MAX_LINE_SIZE];
1634  float in_min[3] = {0.0, 0.0, 0.0};
1635  float in_max[3] = {1.0, 1.0, 1.0};
1636  float out_min[3] = {0.0, 0.0, 0.0};
1637  float out_max[3] = {1.0, 1.0, 1.0};
1638  int inside_metadata = 0, size;
1639 
1641  if (strncmp(line, "CSPLUTV100", 10)) {
1642  av_log(ctx, AV_LOG_ERROR, "Not cineSpace LUT format\n");
1643  return AVERROR(EINVAL);
1644  }
1645 
1647  if (strncmp(line, "1D", 2)) {
1648  av_log(ctx, AV_LOG_ERROR, "Not 1D LUT format\n");
1649  return AVERROR(EINVAL);
1650  }
1651 
1652  while (1) {
1654 
1655  if (!strncmp(line, "BEGIN METADATA", 14)) {
1656  inside_metadata = 1;
1657  continue;
1658  }
1659  if (!strncmp(line, "END METADATA", 12)) {
1660  inside_metadata = 0;
1661  continue;
1662  }
1663  if (inside_metadata == 0) {
1664  for (int i = 0; i < 3; i++) {
1665  int npoints = strtol(line, NULL, 0);
1666 
1667  if (npoints != 2) {
1668  av_log(ctx, AV_LOG_ERROR, "Unsupported number of pre-lut points.\n");
1669  return AVERROR_PATCHWELCOME;
1670  }
1671 
1673  if (av_sscanf(line, "%f %f", &in_min[i], &in_max[i]) != 2)
1674  return AVERROR_INVALIDDATA;
1676  if (av_sscanf(line, "%f %f", &out_min[i], &out_max[i]) != 2)
1677  return AVERROR_INVALIDDATA;
1679  }
1680 
1681  size = strtol(line, NULL, 0);
1682 
1683  if (size < 2 || size > MAX_1D_LEVEL) {
1684  av_log(ctx, AV_LOG_ERROR, "Too large or invalid 1D LUT size\n");
1685  return AVERROR(EINVAL);
1686  }
1687 
1688  lut1d->lutsize = size;
1689 
1690  for (int i = 0; i < size; i++) {
1692  if (av_sscanf(line, "%f %f %f", &lut1d->lut[0][i], &lut1d->lut[1][i], &lut1d->lut[2][i]) != 3)
1693  return AVERROR_INVALIDDATA;
1694  lut1d->lut[0][i] *= out_max[0] - out_min[0];
1695  lut1d->lut[1][i] *= out_max[1] - out_min[1];
1696  lut1d->lut[2][i] *= out_max[2] - out_min[2];
1697  }
1698 
1699  break;
1700  }
1701  }
1702 
1703  lut1d->scale.r = av_clipf(1. / (in_max[0] - in_min[0]), 0.f, 1.f);
1704  lut1d->scale.g = av_clipf(1. / (in_max[1] - in_min[1]), 0.f, 1.f);
1705  lut1d->scale.b = av_clipf(1. / (in_max[2] - in_min[2]), 0.f, 1.f);
1706 
1707  return 0;
1708 }
1709 
1710 static int parse_cube_1d(AVFilterContext *ctx, FILE *f)
1711 {
1712  LUT1DContext *lut1d = ctx->priv;
1713  char line[MAX_LINE_SIZE];
1714  float min[3] = {0.0, 0.0, 0.0};
1715  float max[3] = {1.0, 1.0, 1.0};
1716 
1717  while (fgets(line, sizeof(line), f)) {
1718  if (!strncmp(line, "LUT_1D_SIZE", 11)) {
1719  const int size = strtol(line + 12, NULL, 0);
1720  int i;
1721 
1722  if (size < 2 || size > MAX_1D_LEVEL) {
1723  av_log(ctx, AV_LOG_ERROR, "Too large or invalid 1D LUT size\n");
1724  return AVERROR(EINVAL);
1725  }
1726  lut1d->lutsize = size;
1727  for (i = 0; i < size; i++) {
1728  do {
1729 try_again:
1730  NEXT_LINE(0);
1731  if (!strncmp(line, "DOMAIN_", 7)) {
1732  float *vals = NULL;
1733  if (!strncmp(line + 7, "MIN ", 4)) vals = min;
1734  else if (!strncmp(line + 7, "MAX ", 4)) vals = max;
1735  if (!vals)
1736  return AVERROR_INVALIDDATA;
1737  av_sscanf(line + 11, "%f %f %f", vals, vals + 1, vals + 2);
1738  av_log(ctx, AV_LOG_DEBUG, "min: %f %f %f | max: %f %f %f\n",
1739  min[0], min[1], min[2], max[0], max[1], max[2]);
1740  goto try_again;
1741  } else if (!strncmp(line, "LUT_1D_INPUT_RANGE ", 19)) {
1742  av_sscanf(line + 19, "%f %f", min, max);
1743  min[1] = min[2] = min[0];
1744  max[1] = max[2] = max[0];
1745  goto try_again;
1746  } else if (!strncmp(line, "TITLE", 5)) {
1747  goto try_again;
1748  }
1749  } while (skip_line(line));
1750  if (av_sscanf(line, "%f %f %f", &lut1d->lut[0][i], &lut1d->lut[1][i], &lut1d->lut[2][i]) != 3)
1751  return AVERROR_INVALIDDATA;
1752  }
1753  break;
1754  }
1755  }
1756 
1757  lut1d->scale.r = av_clipf(1. / (max[0] - min[0]), 0.f, 1.f);
1758  lut1d->scale.g = av_clipf(1. / (max[1] - min[1]), 0.f, 1.f);
1759  lut1d->scale.b = av_clipf(1. / (max[2] - min[2]), 0.f, 1.f);
1760 
1761  return 0;
1762 }
1763 
1764 static const AVOption lut1d_options[] = {
1765  { "file", "set 1D LUT file name", OFFSET(file), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = TFLAGS },
1766  { "interp", "select interpolation mode", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=INTERPOLATE_1D_LINEAR}, 0, NB_INTERP_1D_MODE-1, TFLAGS, .unit = "interp_mode" },
1767  { "nearest", "use values from the nearest defined points", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_NEAREST}, 0, 0, TFLAGS, .unit = "interp_mode" },
1768  { "linear", "use values from the linear interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_LINEAR}, 0, 0, TFLAGS, .unit = "interp_mode" },
1769  { "cosine", "use values from the cosine interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_COSINE}, 0, 0, TFLAGS, .unit = "interp_mode" },
1770  { "cubic", "use values from the cubic interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_CUBIC}, 0, 0, TFLAGS, .unit = "interp_mode" },
1771  { "spline", "use values from the spline interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_SPLINE}, 0, 0, TFLAGS, .unit = "interp_mode" },
1772  { NULL }
1773 };
1774 
1775 AVFILTER_DEFINE_CLASS(lut1d);
1776 
1777 static inline float interp_1d_nearest(const LUT1DContext *lut1d,
1778  int idx, const float s)
1779 {
1780  return lut1d->lut[idx][NEAR(s)];
1781 }
1782 
1783 #define NEXT1D(x) (FFMIN((int)(x) + 1, lut1d->lutsize - 1))
1784 
1785 static inline float interp_1d_linear(const LUT1DContext *lut1d,
1786  int idx, const float s)
1787 {
1788  const int prev = PREV(s);
1789  const int next = NEXT1D(s);
1790  const float d = s - prev;
1791  const float p = lut1d->lut[idx][prev];
1792  const float n = lut1d->lut[idx][next];
1793 
1794  return lerpf(p, n, d);
1795 }
1796 
1797 static inline float interp_1d_cosine(const LUT1DContext *lut1d,
1798  int idx, const float s)
1799 {
1800  const int prev = PREV(s);
1801  const int next = NEXT1D(s);
1802  const float d = s - prev;
1803  const float p = lut1d->lut[idx][prev];
1804  const float n = lut1d->lut[idx][next];
1805  const float m = (1.f - cosf(d * M_PI)) * .5f;
1806 
1807  return lerpf(p, n, m);
1808 }
1809 
1810 static inline float interp_1d_cubic(const LUT1DContext *lut1d,
1811  int idx, const float s)
1812 {
1813  const int prev = PREV(s);
1814  const int next = NEXT1D(s);
1815  const float mu = s - prev;
1816  float a0, a1, a2, a3, mu2;
1817 
1818  float y0 = lut1d->lut[idx][FFMAX(prev - 1, 0)];
1819  float y1 = lut1d->lut[idx][prev];
1820  float y2 = lut1d->lut[idx][next];
1821  float y3 = lut1d->lut[idx][FFMIN(next + 1, lut1d->lutsize - 1)];
1822 
1823 
1824  mu2 = mu * mu;
1825  a0 = y3 - y2 - y0 + y1;
1826  a1 = y0 - y1 - a0;
1827  a2 = y2 - y0;
1828  a3 = y1;
1829 
1830  return a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3;
1831 }
1832 
1833 static inline float interp_1d_spline(const LUT1DContext *lut1d,
1834  int idx, const float s)
1835 {
1836  const int prev = PREV(s);
1837  const int next = NEXT1D(s);
1838  const float x = s - prev;
1839  float c0, c1, c2, c3;
1840 
1841  float y0 = lut1d->lut[idx][FFMAX(prev - 1, 0)];
1842  float y1 = lut1d->lut[idx][prev];
1843  float y2 = lut1d->lut[idx][next];
1844  float y3 = lut1d->lut[idx][FFMIN(next + 1, lut1d->lutsize - 1)];
1845 
1846  c0 = y1;
1847  c1 = .5f * (y2 - y0);
1848  c2 = y0 - 2.5f * y1 + 2.f * y2 - .5f * y3;
1849  c3 = .5f * (y3 - y0) + 1.5f * (y1 - y2);
1850 
1851  return ((c3 * x + c2) * x + c1) * x + c0;
1852 }
1853 
1854 #define DEFINE_INTERP_FUNC_PLANAR_1D(name, nbits, depth) \
1855 static int interp_1d_##nbits##_##name##_p##depth(AVFilterContext *ctx, \
1856  void *arg, int jobnr, \
1857  int nb_jobs) \
1858 { \
1859  int x, y; \
1860  const LUT1DContext *lut1d = ctx->priv; \
1861  const ThreadData *td = arg; \
1862  const AVFrame *in = td->in; \
1863  const AVFrame *out = td->out; \
1864  const int direct = out == in; \
1865  const int slice_start = (in->height * jobnr ) / nb_jobs; \
1866  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
1867  uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
1868  uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
1869  uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
1870  uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
1871  const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
1872  const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
1873  const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
1874  const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
1875  const float factor = (1 << depth) - 1; \
1876  const float scale_r = (lut1d->scale.r / factor) * (lut1d->lutsize - 1); \
1877  const float scale_g = (lut1d->scale.g / factor) * (lut1d->lutsize - 1); \
1878  const float scale_b = (lut1d->scale.b / factor) * (lut1d->lutsize - 1); \
1879  \
1880  for (y = slice_start; y < slice_end; y++) { \
1881  uint##nbits##_t *dstg = (uint##nbits##_t *)grow; \
1882  uint##nbits##_t *dstb = (uint##nbits##_t *)brow; \
1883  uint##nbits##_t *dstr = (uint##nbits##_t *)rrow; \
1884  uint##nbits##_t *dsta = (uint##nbits##_t *)arow; \
1885  const uint##nbits##_t *srcg = (const uint##nbits##_t *)srcgrow; \
1886  const uint##nbits##_t *srcb = (const uint##nbits##_t *)srcbrow; \
1887  const uint##nbits##_t *srcr = (const uint##nbits##_t *)srcrrow; \
1888  const uint##nbits##_t *srca = (const uint##nbits##_t *)srcarow; \
1889  for (x = 0; x < in->width; x++) { \
1890  float r = srcr[x] * scale_r; \
1891  float g = srcg[x] * scale_g; \
1892  float b = srcb[x] * scale_b; \
1893  r = interp_1d_##name(lut1d, 0, r); \
1894  g = interp_1d_##name(lut1d, 1, g); \
1895  b = interp_1d_##name(lut1d, 2, b); \
1896  dstr[x] = av_clip_uintp2(r * factor, depth); \
1897  dstg[x] = av_clip_uintp2(g * factor, depth); \
1898  dstb[x] = av_clip_uintp2(b * factor, depth); \
1899  if (!direct && in->linesize[3]) \
1900  dsta[x] = srca[x]; \
1901  } \
1902  grow += out->linesize[0]; \
1903  brow += out->linesize[1]; \
1904  rrow += out->linesize[2]; \
1905  arow += out->linesize[3]; \
1906  srcgrow += in->linesize[0]; \
1907  srcbrow += in->linesize[1]; \
1908  srcrrow += in->linesize[2]; \
1909  srcarow += in->linesize[3]; \
1910  } \
1911  return 0; \
1912 }
1913 
1914 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 8, 8)
1915 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 8, 8)
1916 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 8, 8)
1917 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 8, 8)
1918 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 8, 8)
1919 
1920 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 9)
1921 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 9)
1922 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 9)
1923 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 9)
1924 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 9)
1925 
1926 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 10)
1927 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 10)
1928 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 10)
1929 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 10)
1930 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 10)
1931 
1932 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 12)
1933 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 12)
1934 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 12)
1935 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 12)
1936 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 12)
1937 
1938 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 14)
1939 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 14)
1940 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 14)
1941 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 14)
1942 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 14)
1943 
1944 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 16)
1945 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 16)
1946 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 16)
1947 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 16)
1948 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 16)
1949 
1950 #define DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(name, depth) \
1951 static int interp_1d_##name##_pf##depth(AVFilterContext *ctx, \
1952  void *arg, int jobnr, \
1953  int nb_jobs) \
1954 { \
1955  int x, y; \
1956  const LUT1DContext *lut1d = ctx->priv; \
1957  const ThreadData *td = arg; \
1958  const AVFrame *in = td->in; \
1959  const AVFrame *out = td->out; \
1960  const int direct = out == in; \
1961  const int slice_start = (in->height * jobnr ) / nb_jobs; \
1962  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
1963  uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
1964  uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
1965  uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
1966  uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
1967  const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
1968  const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
1969  const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
1970  const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
1971  const float lutsize = lut1d->lutsize - 1; \
1972  const float scale_r = lut1d->scale.r * lutsize; \
1973  const float scale_g = lut1d->scale.g * lutsize; \
1974  const float scale_b = lut1d->scale.b * lutsize; \
1975  \
1976  for (y = slice_start; y < slice_end; y++) { \
1977  float *dstg = (float *)grow; \
1978  float *dstb = (float *)brow; \
1979  float *dstr = (float *)rrow; \
1980  float *dsta = (float *)arow; \
1981  const float *srcg = (const float *)srcgrow; \
1982  const float *srcb = (const float *)srcbrow; \
1983  const float *srcr = (const float *)srcrrow; \
1984  const float *srca = (const float *)srcarow; \
1985  for (x = 0; x < in->width; x++) { \
1986  float r = av_clipf(sanitizef(srcr[x]) * scale_r, 0.0f, lutsize); \
1987  float g = av_clipf(sanitizef(srcg[x]) * scale_g, 0.0f, lutsize); \
1988  float b = av_clipf(sanitizef(srcb[x]) * scale_b, 0.0f, lutsize); \
1989  r = interp_1d_##name(lut1d, 0, r); \
1990  g = interp_1d_##name(lut1d, 1, g); \
1991  b = interp_1d_##name(lut1d, 2, b); \
1992  dstr[x] = r; \
1993  dstg[x] = g; \
1994  dstb[x] = b; \
1995  if (!direct && in->linesize[3]) \
1996  dsta[x] = srca[x]; \
1997  } \
1998  grow += out->linesize[0]; \
1999  brow += out->linesize[1]; \
2000  rrow += out->linesize[2]; \
2001  arow += out->linesize[3]; \
2002  srcgrow += in->linesize[0]; \
2003  srcbrow += in->linesize[1]; \
2004  srcrrow += in->linesize[2]; \
2005  srcarow += in->linesize[3]; \
2006  } \
2007  return 0; \
2008 }
2009 
2010 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(nearest, 32)
2011 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(linear, 32)
2012 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(cosine, 32)
2013 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(cubic, 32)
2014 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(spline, 32)
2015 
2016 #define DEFINE_INTERP_FUNC_1D(name, nbits) \
2017 static int interp_1d_##nbits##_##name(AVFilterContext *ctx, void *arg, \
2018  int jobnr, int nb_jobs) \
2019 { \
2020  int x, y; \
2021  const LUT1DContext *lut1d = ctx->priv; \
2022  const ThreadData *td = arg; \
2023  const AVFrame *in = td->in; \
2024  const AVFrame *out = td->out; \
2025  const int direct = out == in; \
2026  const int step = lut1d->step; \
2027  const uint8_t r = lut1d->rgba_map[R]; \
2028  const uint8_t g = lut1d->rgba_map[G]; \
2029  const uint8_t b = lut1d->rgba_map[B]; \
2030  const uint8_t a = lut1d->rgba_map[A]; \
2031  const int slice_start = (in->height * jobnr ) / nb_jobs; \
2032  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
2033  uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \
2034  const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \
2035  const float factor = (1 << nbits) - 1; \
2036  const float scale_r = (lut1d->scale.r / factor) * (lut1d->lutsize - 1); \
2037  const float scale_g = (lut1d->scale.g / factor) * (lut1d->lutsize - 1); \
2038  const float scale_b = (lut1d->scale.b / factor) * (lut1d->lutsize - 1); \
2039  \
2040  for (y = slice_start; y < slice_end; y++) { \
2041  uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \
2042  const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \
2043  for (x = 0; x < in->width * step; x += step) { \
2044  float rr = src[x + r] * scale_r; \
2045  float gg = src[x + g] * scale_g; \
2046  float bb = src[x + b] * scale_b; \
2047  rr = interp_1d_##name(lut1d, 0, rr); \
2048  gg = interp_1d_##name(lut1d, 1, gg); \
2049  bb = interp_1d_##name(lut1d, 2, bb); \
2050  dst[x + r] = av_clip_uint##nbits(rr * factor); \
2051  dst[x + g] = av_clip_uint##nbits(gg * factor); \
2052  dst[x + b] = av_clip_uint##nbits(bb * factor); \
2053  if (!direct && step == 4) \
2054  dst[x + a] = src[x + a]; \
2055  } \
2056  dstrow += out->linesize[0]; \
2057  srcrow += in ->linesize[0]; \
2058  } \
2059  return 0; \
2060 }
2061 
2062 DEFINE_INTERP_FUNC_1D(nearest, 8)
2063 DEFINE_INTERP_FUNC_1D(linear, 8)
2064 DEFINE_INTERP_FUNC_1D(cosine, 8)
2065 DEFINE_INTERP_FUNC_1D(cubic, 8)
2066 DEFINE_INTERP_FUNC_1D(spline, 8)
2067 
2068 DEFINE_INTERP_FUNC_1D(nearest, 16)
2069 DEFINE_INTERP_FUNC_1D(linear, 16)
2070 DEFINE_INTERP_FUNC_1D(cosine, 16)
2071 DEFINE_INTERP_FUNC_1D(cubic, 16)
2072 DEFINE_INTERP_FUNC_1D(spline, 16)
2073 
2074 static int config_input_1d(AVFilterLink *inlink)
2075 {
2076  int depth, is16bit, isfloat, planar;
2077  LUT1DContext *lut1d = inlink->dst->priv;
2079 
2080  depth = desc->comp[0].depth;
2081  is16bit = desc->comp[0].depth > 8;
2082  planar = desc->flags & AV_PIX_FMT_FLAG_PLANAR;
2083  isfloat = desc->flags & AV_PIX_FMT_FLAG_FLOAT;
2084  ff_fill_rgba_map(lut1d->rgba_map, inlink->format);
2085  lut1d->step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit);
2086 
2087 #define SET_FUNC_1D(name) do { \
2088  if (planar && !isfloat) { \
2089  switch (depth) { \
2090  case 8: lut1d->interp = interp_1d_8_##name##_p8; break; \
2091  case 9: lut1d->interp = interp_1d_16_##name##_p9; break; \
2092  case 10: lut1d->interp = interp_1d_16_##name##_p10; break; \
2093  case 12: lut1d->interp = interp_1d_16_##name##_p12; break; \
2094  case 14: lut1d->interp = interp_1d_16_##name##_p14; break; \
2095  case 16: lut1d->interp = interp_1d_16_##name##_p16; break; \
2096  } \
2097  } else if (isfloat) { lut1d->interp = interp_1d_##name##_pf32; \
2098  } else if (is16bit) { lut1d->interp = interp_1d_16_##name; \
2099  } else { lut1d->interp = interp_1d_8_##name; } \
2100 } while (0)
2101 
2102  switch (lut1d->interpolation) {
2103  case INTERPOLATE_1D_NEAREST: SET_FUNC_1D(nearest); break;
2104  case INTERPOLATE_1D_LINEAR: SET_FUNC_1D(linear); break;
2105  case INTERPOLATE_1D_COSINE: SET_FUNC_1D(cosine); break;
2106  case INTERPOLATE_1D_CUBIC: SET_FUNC_1D(cubic); break;
2107  case INTERPOLATE_1D_SPLINE: SET_FUNC_1D(spline); break;
2108  default:
2109  av_assert0(0);
2110  }
2111 
2112  return 0;
2113 }
2114 
2115 static av_cold int lut1d_init(AVFilterContext *ctx)
2116 {
2117  int ret;
2118  FILE *f;
2119  const char *ext;
2120  LUT1DContext *lut1d = ctx->priv;
2121 
2122  lut1d->scale.r = lut1d->scale.g = lut1d->scale.b = 1.f;
2123 
2124  if (!lut1d->file) {
2125  set_identity_matrix_1d(lut1d, 32);
2126  return 0;
2127  }
2128 
2129  f = avpriv_fopen_utf8(lut1d->file, "r");
2130  if (!f) {
2131  ret = AVERROR(errno);
2132  av_log(ctx, AV_LOG_ERROR, "%s: %s\n", lut1d->file, av_err2str(ret));
2133  return ret;
2134  }
2135 
2136  ext = strrchr(lut1d->file, '.');
2137  if (!ext) {
2138  av_log(ctx, AV_LOG_ERROR, "Unable to guess the format from the extension\n");
2140  goto end;
2141  }
2142  ext++;
2143 
2144  if (!av_strcasecmp(ext, "cube") || !av_strcasecmp(ext, "1dlut")) {
2145  ret = parse_cube_1d(ctx, f);
2146  } else if (!av_strcasecmp(ext, "csp")) {
2147  ret = parse_cinespace_1d(ctx, f);
2148  } else {
2149  av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext);
2150  ret = AVERROR(EINVAL);
2151  }
2152 
2153  if (!ret && !lut1d->lutsize) {
2154  av_log(ctx, AV_LOG_ERROR, "1D LUT is empty\n");
2156  }
2157 
2158 end:
2159  fclose(f);
2160  return ret;
2161 }
2162 
2163 static AVFrame *apply_1d_lut(AVFilterLink *inlink, AVFrame *in)
2164 {
2165  AVFilterContext *ctx = inlink->dst;
2166  LUT1DContext *lut1d = ctx->priv;
2167  AVFilterLink *outlink = inlink->dst->outputs[0];
2168  AVFrame *out;
2169  ThreadData td;
2170 
2171  if (av_frame_is_writable(in)) {
2172  out = in;
2173  } else {
2174  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
2175  if (!out) {
2176  av_frame_free(&in);
2177  return NULL;
2178  }
2179  av_frame_copy_props(out, in);
2180  }
2181 
2182  td.in = in;
2183  td.out = out;
2184  ff_filter_execute(ctx, lut1d->interp, &td, NULL,
2185  FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
2186 
2187  if (out != in)
2188  av_frame_free(&in);
2189 
2190  return out;
2191 }
2192 
2193 static int filter_frame_1d(AVFilterLink *inlink, AVFrame *in)
2194 {
2195  AVFilterLink *outlink = inlink->dst->outputs[0];
2196  AVFrame *out = apply_1d_lut(inlink, in);
2197  if (!out)
2198  return AVERROR(ENOMEM);
2199  return ff_filter_frame(outlink, out);
2200 }
2201 
2202 static int lut1d_process_command(AVFilterContext *ctx, const char *cmd, const char *args,
2203  char *res, int res_len, int flags)
2204 {
2205  LUT1DContext *lut1d = ctx->priv;
2206  int ret;
2207 
2208  ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
2209  if (ret < 0)
2210  return ret;
2211 
2212  ret = lut1d_init(ctx);
2213  if (ret < 0) {
2214  set_identity_matrix_1d(lut1d, 32);
2215  return ret;
2216  }
2217  return config_input_1d(ctx->inputs[0]);
2218 }
2219 
2220 static const AVFilterPad lut1d_inputs[] = {
2221  {
2222  .name = "default",
2223  .type = AVMEDIA_TYPE_VIDEO,
2224  .filter_frame = filter_frame_1d,
2225  .config_props = config_input_1d,
2226  },
2227 };
2228 
2229 const AVFilter ff_vf_lut1d = {
2230  .name = "lut1d",
2231  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a 1D LUT."),
2232  .priv_size = sizeof(LUT1DContext),
2233  .init = lut1d_init,
2234  FILTER_INPUTS(lut1d_inputs),
2237  .priv_class = &lut1d_class,
2239  .process_command = lut1d_process_command,
2240 };
2241 #endif
apply_lut
static AVFrame * apply_lut(AVFilterLink *inlink, AVFrame *in)
Definition: vf_lut3d.c:1159
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:112
COMMON_OPTIONS
#define COMMON_OPTIONS
Definition: vf_lut3d.c:50
config_input
static int config_input(AVFilterLink *inlink)
Definition: vf_lut3d.c:1114
AV_PIX_FMT_GBRAP16
#define AV_PIX_FMT_GBRAP16
Definition: pixfmt.h:501
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:134
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
td
#define td
Definition: regdef.h:70
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h: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:767
ff_framesync_uninit
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition: framesync.c:304
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:864
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1015
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:796
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2965
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
FILTER_PIXFMTS_ARRAY
#define FILTER_PIXFMTS_ARRAY(array)
Definition: internal.h:162
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:160
LUT3DContext::scale
struct rgbvec scale
Definition: lut3d.h:61
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:375
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:346
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:148
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:49
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:170
c1
static const uint64_t c1
Definition: murmur3.c:52
AVFILTER_DEFINE_CLASS_EXT
#define AVFILTER_DEFINE_CLASS_EXT(name, desc, options)
Definition: internal.h:315
FFFrameSync
Frame sync structure.
Definition: framesync.h:168
parse_cube
static int parse_cube(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:675
intfloat.h
video.h
ff_vf_lut3d
const AVFilter ff_vf_lut3d
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
process_command
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: vf_lut3d.c:1198
INTERPOLATE_PYRAMID
@ INTERPOLATE_PYRAMID
Definition: lut3d.h:34
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:30
Lut3DPreLut::lut
float * lut[3]
Definition: lut3d.h:53
av_pix_fmt_count_planes
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3005
parse_3dl
static int parse_3dl(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:732
AV_PIX_FMT_GBRP14
#define AV_PIX_FMT_GBRP14
Definition: pixfmt.h:496
AV_PIX_FMT_GBRAP
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
Definition: pixfmt.h:212
v0
#define v0
Definition: regdef.h:26
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:494
val
static double val(void *priv, double ch)
Definition: aeval.c:78
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: internal.h:33
a1
#define a1
Definition: regdef.h:47
pix_fmts
static enum AVPixelFormat pix_fmts[]
Definition: vf_lut3d.c:1096
SET_COLOR
#define SET_COLOR(id)
INTERPOLATE_NEAREST
@ INTERPOLATE_NEAREST
Definition: lut3d.h:31
avassert.h
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
LUT3DContext::file
char * file
Definition: lut3d.h:63
av_cold
#define av_cold
Definition: attributes.h:90
Lut3DPreLut::scale
float scale[3]
Definition: lut3d.h:52
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
AV_PIX_FMT_GBRAP10
#define AV_PIX_FMT_GBRAP10
Definition: pixfmt.h:498
float
float
Definition: af_crystalizer.c:121
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:499
g
const char * g
Definition: vf_curves.c:128
SET_FUNC
#define SET_FUNC(name)
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:40
INTERPOLATE_PRISM
@ INTERPOLATE_PRISM
Definition: lut3d.h:35
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
ctx
AVFormatContext * ctx
Definition: movenc.c: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_INPUTS
#define FILTER_INPUTS(array)
Definition: internal.h:182
file_open.h
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:100
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_lut3d.c:1189
AV_PIX_FMT_GBRP16
#define AV_PIX_FMT_GBRP16
Definition: pixfmt.h:497
AV_PIX_FMT_RGBA64
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:468
av_sscanf
int av_sscanf(const char *string, const char *format,...)
See libc sscanf manual for more information.
Definition: avsscanf.c:962
prelut_interp_1d_linear
static float prelut_interp_1d_linear(const Lut3DPreLut *prelut, int idx, const float s)
Definition: vf_lut3d.c:293
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
rgbvec::r
float r
Definition: lut3d.h:40
AV_PIX_FMT_BGR48
#define AV_PIX_FMT_BGR48
Definition: pixfmt.h:469
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:709
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:347
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
av_clipf
av_clipf
Definition: af_crystalizer.c:121
AV_PIX_FMT_GBRP9
#define AV_PIX_FMT_GBRP9
Definition: pixfmt.h:493
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:121
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:366
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:375
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:2930
config_output
static int config_output(AVFilterLink *outlink)
Definition: af_aap.c:191
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:121
AV_PIX_FMT_GBRPF32
#define AV_PIX_FMT_GBRPF32
Definition: pixfmt.h:508
AV_PIX_FMT_RGB48
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:464
size
int size
Definition: twinvq_data.h:10344
Lut3DPreLut::min
float min[3]
Definition: lut3d.h:50
av_frame_is_writable
int av_frame_is_writable(AVFrame *frame)
Check if the frame data is writable.
Definition: frame.c:645
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:887
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
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:1071
PREV
#define PREV(x)
Definition: vf_lut3d.c:97
a0
#define a0
Definition: regdef.h:46
interpolation
static int interpolation(DeclickChannel *c, const double *src, int ar_order, double *acoefficients, int *index, int nb_errors, double *auxiliary, double *interpolated)
Definition: af_adeclick.c:390
M_PI
#define M_PI
Definition: mathematics.h:67
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
PRELUT_SIZE
#define PRELUT_SIZE
Definition: lut3d.h:46
internal.h
AVFILTER_DEFINE_CLASS
#define AVFILTER_DEFINE_CLASS(fname)
Definition: internal.h:323
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:147
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:473
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
LUT3DContext::interp
avfilter_action_func * interp
Definition: lut3d.h:66
DEFINE_INTERP_FUNC_PLANAR
#define DEFINE_INTERP_FUNC_PLANAR(name, nbits, depth)
Definition: vf_lut3d.c:321
AV_PIX_FMT_GBRP12
#define AV_PIX_FMT_GBRP12
Definition: pixfmt.h:495
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:31
a2
#define a2
Definition: regdef.h:48
ff_filter_get_nb_threads
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:827
ThreadData
Used for passing data between threads.
Definition: dsddec.c:71
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
INTERPOLATE_TETRAHEDRAL
@ INTERPOLATE_TETRAHEDRAL
Definition: lut3d.h:33
Lut3DPreLut::max
float max[3]
Definition: lut3d.h:51
interp_pyramid
static struct rgbvec interp_pyramid(const LUT3DContext *lut3d, const struct rgbvec *s)
Definition: vf_lut3d.c:139
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:39
avpriv_fopen_utf8
FILE * avpriv_fopen_utf8(const char *path, const char *mode)
Open a file using a UTF-8 filename.
Definition: file_open.c:159
parse_cinespace
static int parse_cinespace(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:874
Lut3DPreLut
Definition: lut3d.h:48
AVFilter
Filter definition.
Definition: avfilter.h:166
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
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
Definition: opt.h:235
AV_PIX_FMT_GBRAPF32
#define AV_PIX_FMT_GBRAPF32
Definition: pixfmt.h:509
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:407
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:117
desc
const char * desc
Definition: libsvtav1.c:75
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
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:183
INTERPOLATE_TRILINEAR
@ INTERPOLATE_TRILINEAR
Definition: lut3d.h:32
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:35
ff_lut3d_init_x86
void ff_lut3d_init_x86(LUT3DContext *s, const AVPixFmtDescriptor *desc)
Definition: vf_lut3d_init.c:58
d
d
Definition: ffmpeg_filter.c:424
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:155
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:474
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
h
h
Definition: vp9dsp_template.c:2038
ff_framesync_activate
int ff_framesync_activate(FFFrameSync *fs)
Examine the frames in the filter's input and try to produce output.
Definition: framesync.c:355
ff_vf_lut1d
const AVFilter ff_vf_lut1d
avstring.h
ff_framesync_dualinput_get
int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1)
Definition: framesync.c:393
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:239
drawutils.h
ff_filter_execute
static av_always_inline int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
Definition: internal.h:134
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:244
a3
#define a3
Definition: regdef.h:49
LUT3DContext::lutsize
int lutsize
Definition: lut3d.h:59
LUT3DContext::lut
struct rgbvec * lut
Definition: lut3d.h:58
LUT3DContext::interpolation
int interpolation
interp_mode
Definition: lut3d.h:62
LUT3DContext::rgba_map
uint8_t rgba_map[4]
Definition: lut3d.h:64
min
float min
Definition: vorbis_enc_data.h:429
nearest_sample_index
static int nearest_sample_index(float *data, float x, int low, int hi)
Definition: vf_lut3d.c:836