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