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