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 0x80000000
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_MAX;
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_MAX;
882  out_min[i] = FLT_MAX;
883  out_max[i] = -FLT_MAX;
884 
885  for (int j = 0; j < npoints; j++) {
887  in_min[i] = FFMIN(in_min[i], v);
888  in_max[i] = FFMAX(in_max[i], v);
889  in_prelut[i][j] = v;
890  if (j > 0 && v < last) {
891  av_log(ctx, AV_LOG_ERROR, "Invalid file, non increasing prelut.\n");
892  ret = AVERROR(ENOMEM);
893  goto end;
894  }
895  last = v;
896  }
897 
898  for (int j = 0; j < npoints; j++) {
900  out_min[i] = FFMIN(out_min[i], v);
901  out_max[i] = FFMAX(out_max[i], v);
902  out_prelut[i][j] = v;
903  }
904 
905  } else if (npoints == 2) {
907  if (av_sscanf(line, "%f %f", &in_min[i], &in_max[i]) != 2) {
908  ret = AVERROR_INVALIDDATA;
909  goto end;
910  }
912  if (av_sscanf(line, "%f %f", &out_min[i], &out_max[i]) != 2) {
913  ret = AVERROR_INVALIDDATA;
914  goto end;
915  }
916 
917  } else {
918  av_log(ctx, AV_LOG_ERROR, "Unsupported number of pre-lut points.\n");
919  ret = AVERROR_PATCHWELCOME;
920  goto end;
921  }
922 
924  }
925 
926  if (av_sscanf(line, "%d %d %d", &size_r, &size_g, &size_b) != 3) {
927  ret = AVERROR(EINVAL);
928  goto end;
929  }
930  if (size_r != size_g || size_r != size_b) {
931  av_log(ctx, AV_LOG_ERROR, "Unsupported size combination: %dx%dx%d.\n", size_r, size_g, size_b);
932  ret = AVERROR_PATCHWELCOME;
933  goto end;
934  }
935 
936  size = size_r;
937  size2 = size * size;
938 
939  if (prelut_sizes[0] && prelut_sizes[1] && prelut_sizes[2])
940  prelut = 1;
941 
942  ret = allocate_3dlut(ctx, size, prelut);
943  if (ret < 0)
944  return ret;
945 
946  for (int k = 0; k < size; k++) {
947  for (int j = 0; j < size; j++) {
948  for (int i = 0; i < size; i++) {
949  struct rgbvec *vec = &lut3d->lut[i * size2 + j * size + k];
950 
952  if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3) {
953  ret = AVERROR_INVALIDDATA;
954  goto end;
955  }
956 
957  vec->r *= out_max[0] - out_min[0];
958  vec->g *= out_max[1] - out_min[1];
959  vec->b *= out_max[2] - out_min[2];
960  }
961  }
962  }
963 
964  break;
965  }
966  }
967 
968  if (prelut) {
969  for (int c = 0; c < 3; c++) {
970 
971  lut3d->prelut.min[c] = in_min[c];
972  lut3d->prelut.max[c] = in_max[c];
973  lut3d->prelut.scale[c] = (1.0f / (float)(in_max[c] - in_min[c])) * (lut3d->prelut.size - 1);
974 
975  for (int i = 0; i < lut3d->prelut.size; ++i) {
976  float mix = (float) i / (float)(lut3d->prelut.size - 1);
977  float x = lerpf(in_min[c], in_max[c], mix), a, b;
978 
979  int idx = nearest_sample_index(in_prelut[c], x, 0, prelut_sizes[c]-1);
980  av_assert0(idx + 1 < prelut_sizes[c]);
981 
982  a = out_prelut[c][idx + 0];
983  b = out_prelut[c][idx + 1];
984  mix = x - in_prelut[c][idx];
985 
986  lut3d->prelut.lut[c][i] = sanitizef(lerpf(a, b, mix));
987  }
988  }
989  lut3d->scale.r = 1.00f;
990  lut3d->scale.g = 1.00f;
991  lut3d->scale.b = 1.00f;
992 
993  } else {
994  lut3d->scale.r = av_clipf(1. / (in_max[0] - in_min[0]), 0.f, 1.f);
995  lut3d->scale.g = av_clipf(1. / (in_max[1] - in_min[1]), 0.f, 1.f);
996  lut3d->scale.b = av_clipf(1. / (in_max[2] - in_min[2]), 0.f, 1.f);
997  }
998 
999 end:
1000  for (int c = 0; c < 3; c++) {
1001  av_freep(&in_prelut[c]);
1002  av_freep(&out_prelut[c]);
1003  }
1004  return ret;
1005 }
1006 
1008 {
1009  LUT3DContext *lut3d = ctx->priv;
1010  int ret, i, j, k;
1011  const int size2 = size * size;
1012  const float c = 1. / (size - 1);
1013 
1014  ret = allocate_3dlut(ctx, size, 0);
1015  if (ret < 0)
1016  return ret;
1017 
1018  for (k = 0; k < size; k++) {
1019  for (j = 0; j < size; j++) {
1020  for (i = 0; i < size; i++) {
1021  struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i];
1022  vec->r = k * c;
1023  vec->g = j * c;
1024  vec->b = i * c;
1025  }
1026  }
1027  }
1028 
1029  return 0;
1030 }
1031 
1033 {
1034  static const enum AVPixelFormat pix_fmts[] = {
1050  };
1051  AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
1052  if (!fmts_list)
1053  return AVERROR(ENOMEM);
1054  return ff_set_common_formats(ctx, fmts_list);
1055 }
1056 
1058 {
1059  int depth, is16bit, isfloat, planar;
1060  LUT3DContext *lut3d = inlink->dst->priv;
1062 
1063  depth = desc->comp[0].depth;
1064  is16bit = desc->comp[0].depth > 8;
1065  planar = desc->flags & AV_PIX_FMT_FLAG_PLANAR;
1066  isfloat = desc->flags & AV_PIX_FMT_FLAG_FLOAT;
1067  ff_fill_rgba_map(lut3d->rgba_map, inlink->format);
1068  lut3d->step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit);
1069 
1070 #define SET_FUNC(name) do { \
1071  if (planar && !isfloat) { \
1072  switch (depth) { \
1073  case 8: lut3d->interp = interp_8_##name##_p8; break; \
1074  case 9: lut3d->interp = interp_16_##name##_p9; break; \
1075  case 10: lut3d->interp = interp_16_##name##_p10; break; \
1076  case 12: lut3d->interp = interp_16_##name##_p12; break; \
1077  case 14: lut3d->interp = interp_16_##name##_p14; break; \
1078  case 16: lut3d->interp = interp_16_##name##_p16; break; \
1079  } \
1080  } else if (isfloat) { lut3d->interp = interp_##name##_pf32; \
1081  } else if (is16bit) { lut3d->interp = interp_16_##name; \
1082  } else { lut3d->interp = interp_8_##name; } \
1083 } while (0)
1084 
1085  switch (lut3d->interpolation) {
1086  case INTERPOLATE_NEAREST: SET_FUNC(nearest); break;
1087  case INTERPOLATE_TRILINEAR: SET_FUNC(trilinear); break;
1088  case INTERPOLATE_TETRAHEDRAL: SET_FUNC(tetrahedral); break;
1089  default:
1090  av_assert0(0);
1091  }
1092 
1093  return 0;
1094 }
1095 
1097 {
1098  AVFilterContext *ctx = inlink->dst;
1099  LUT3DContext *lut3d = ctx->priv;
1100  AVFilterLink *outlink = inlink->dst->outputs[0];
1101  AVFrame *out;
1102  ThreadData td;
1103 
1104  if (av_frame_is_writable(in)) {
1105  out = in;
1106  } else {
1107  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
1108  if (!out) {
1109  av_frame_free(&in);
1110  return NULL;
1111  }
1112  av_frame_copy_props(out, in);
1113  }
1114 
1115  td.in = in;
1116  td.out = out;
1117  ctx->internal->execute(ctx, lut3d->interp, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
1118 
1119  if (out != in)
1120  av_frame_free(&in);
1121 
1122  return out;
1123 }
1124 
1126 {
1127  AVFilterLink *outlink = inlink->dst->outputs[0];
1128  AVFrame *out = apply_lut(inlink, in);
1129  if (!out)
1130  return AVERROR(ENOMEM);
1131  return ff_filter_frame(outlink, out);
1132 }
1133 
1134 #if CONFIG_LUT3D_FILTER
1135 static const AVOption lut3d_options[] = {
1136  { "file", "set 3D LUT file name", OFFSET(file), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
1138 };
1139 
1140 AVFILTER_DEFINE_CLASS(lut3d);
1141 
1142 static av_cold int lut3d_init(AVFilterContext *ctx)
1143 {
1144  int ret;
1145  FILE *f;
1146  const char *ext;
1147  LUT3DContext *lut3d = ctx->priv;
1148 
1149  lut3d->scale.r = lut3d->scale.g = lut3d->scale.b = 1.f;
1150 
1151  if (!lut3d->file) {
1152  return set_identity_matrix(ctx, 32);
1153  }
1154 
1155  f = av_fopen_utf8(lut3d->file, "r");
1156  if (!f) {
1157  ret = AVERROR(errno);
1158  av_log(ctx, AV_LOG_ERROR, "%s: %s\n", lut3d->file, av_err2str(ret));
1159  return ret;
1160  }
1161 
1162  ext = strrchr(lut3d->file, '.');
1163  if (!ext) {
1164  av_log(ctx, AV_LOG_ERROR, "Unable to guess the format from the extension\n");
1165  ret = AVERROR_INVALIDDATA;
1166  goto end;
1167  }
1168  ext++;
1169 
1170  if (!av_strcasecmp(ext, "dat")) {
1171  ret = parse_dat(ctx, f);
1172  } else if (!av_strcasecmp(ext, "3dl")) {
1173  ret = parse_3dl(ctx, f);
1174  } else if (!av_strcasecmp(ext, "cube")) {
1175  ret = parse_cube(ctx, f);
1176  } else if (!av_strcasecmp(ext, "m3d")) {
1177  ret = parse_m3d(ctx, f);
1178  } else if (!av_strcasecmp(ext, "csp")) {
1179  ret = parse_cinespace(ctx, f);
1180  } else {
1181  av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext);
1182  ret = AVERROR(EINVAL);
1183  }
1184 
1185  if (!ret && !lut3d->lutsize) {
1186  av_log(ctx, AV_LOG_ERROR, "3D LUT is empty\n");
1187  ret = AVERROR_INVALIDDATA;
1188  }
1189 
1190 end:
1191  fclose(f);
1192  return ret;
1193 }
1194 
1195 static av_cold void lut3d_uninit(AVFilterContext *ctx)
1196 {
1197  LUT3DContext *lut3d = ctx->priv;
1198  int i;
1199  av_freep(&lut3d->lut);
1200 
1201  for (i = 0; i < 3; i++) {
1202  av_freep(&lut3d->prelut.lut[i]);
1203  }
1204 }
1205 
1206 static const AVFilterPad lut3d_inputs[] = {
1207  {
1208  .name = "default",
1209  .type = AVMEDIA_TYPE_VIDEO,
1210  .filter_frame = filter_frame,
1211  .config_props = config_input,
1212  },
1213  { NULL }
1214 };
1215 
1216 static const AVFilterPad lut3d_outputs[] = {
1217  {
1218  .name = "default",
1219  .type = AVMEDIA_TYPE_VIDEO,
1220  },
1221  { NULL }
1222 };
1223 
1225  .name = "lut3d",
1226  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a 3D LUT."),
1227  .priv_size = sizeof(LUT3DContext),
1228  .init = lut3d_init,
1229  .uninit = lut3d_uninit,
1231  .inputs = lut3d_inputs,
1232  .outputs = lut3d_outputs,
1233  .priv_class = &lut3d_class,
1235 };
1236 #endif
1237 
1238 #if CONFIG_HALDCLUT_FILTER
1239 
1240 static void update_clut_packed(LUT3DContext *lut3d, const AVFrame *frame)
1241 {
1242  const uint8_t *data = frame->data[0];
1243  const int linesize = frame->linesize[0];
1244  const int w = lut3d->clut_width;
1245  const int step = lut3d->clut_step;
1246  const uint8_t *rgba_map = lut3d->clut_rgba_map;
1247  const int level = lut3d->lutsize;
1248  const int level2 = lut3d->lutsize2;
1249 
1250 #define LOAD_CLUT(nbits) do { \
1251  int i, j, k, x = 0, y = 0; \
1252  \
1253  for (k = 0; k < level; k++) { \
1254  for (j = 0; j < level; j++) { \
1255  for (i = 0; i < level; i++) { \
1256  const uint##nbits##_t *src = (const uint##nbits##_t *) \
1257  (data + y*linesize + x*step); \
1258  struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k]; \
1259  vec->r = src[rgba_map[0]] / (float)((1<<(nbits)) - 1); \
1260  vec->g = src[rgba_map[1]] / (float)((1<<(nbits)) - 1); \
1261  vec->b = src[rgba_map[2]] / (float)((1<<(nbits)) - 1); \
1262  if (++x == w) { \
1263  x = 0; \
1264  y++; \
1265  } \
1266  } \
1267  } \
1268  } \
1269 } while (0)
1270 
1271  switch (lut3d->clut_bits) {
1272  case 8: LOAD_CLUT(8); break;
1273  case 16: LOAD_CLUT(16); break;
1274  }
1275 }
1276 
1277 static void update_clut_planar(LUT3DContext *lut3d, const AVFrame *frame)
1278 {
1279  const uint8_t *datag = frame->data[0];
1280  const uint8_t *datab = frame->data[1];
1281  const uint8_t *datar = frame->data[2];
1282  const int glinesize = frame->linesize[0];
1283  const int blinesize = frame->linesize[1];
1284  const int rlinesize = frame->linesize[2];
1285  const int w = lut3d->clut_width;
1286  const int level = lut3d->lutsize;
1287  const int level2 = lut3d->lutsize2;
1288 
1289 #define LOAD_CLUT_PLANAR(nbits, depth) do { \
1290  int i, j, k, x = 0, y = 0; \
1291  \
1292  for (k = 0; k < level; k++) { \
1293  for (j = 0; j < level; j++) { \
1294  for (i = 0; i < level; i++) { \
1295  const uint##nbits##_t *gsrc = (const uint##nbits##_t *) \
1296  (datag + y*glinesize); \
1297  const uint##nbits##_t *bsrc = (const uint##nbits##_t *) \
1298  (datab + y*blinesize); \
1299  const uint##nbits##_t *rsrc = (const uint##nbits##_t *) \
1300  (datar + y*rlinesize); \
1301  struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k]; \
1302  vec->r = gsrc[x] / (float)((1<<(depth)) - 1); \
1303  vec->g = bsrc[x] / (float)((1<<(depth)) - 1); \
1304  vec->b = rsrc[x] / (float)((1<<(depth)) - 1); \
1305  if (++x == w) { \
1306  x = 0; \
1307  y++; \
1308  } \
1309  } \
1310  } \
1311  } \
1312 } while (0)
1313 
1314  switch (lut3d->clut_bits) {
1315  case 8: LOAD_CLUT_PLANAR(8, 8); break;
1316  case 9: LOAD_CLUT_PLANAR(16, 9); break;
1317  case 10: LOAD_CLUT_PLANAR(16, 10); break;
1318  case 12: LOAD_CLUT_PLANAR(16, 12); break;
1319  case 14: LOAD_CLUT_PLANAR(16, 14); break;
1320  case 16: LOAD_CLUT_PLANAR(16, 16); break;
1321  }
1322 }
1323 
1324 static void update_clut_float(LUT3DContext *lut3d, const AVFrame *frame)
1325 {
1326  const uint8_t *datag = frame->data[0];
1327  const uint8_t *datab = frame->data[1];
1328  const uint8_t *datar = frame->data[2];
1329  const int glinesize = frame->linesize[0];
1330  const int blinesize = frame->linesize[1];
1331  const int rlinesize = frame->linesize[2];
1332  const int w = lut3d->clut_width;
1333  const int level = lut3d->lutsize;
1334  const int level2 = lut3d->lutsize2;
1335 
1336  int i, j, k, x = 0, y = 0;
1337 
1338  for (k = 0; k < level; k++) {
1339  for (j = 0; j < level; j++) {
1340  for (i = 0; i < level; i++) {
1341  const float *gsrc = (const float *)(datag + y*glinesize);
1342  const float *bsrc = (const float *)(datab + y*blinesize);
1343  const float *rsrc = (const float *)(datar + y*rlinesize);
1344  struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k];
1345  vec->r = rsrc[x];
1346  vec->g = gsrc[x];
1347  vec->b = bsrc[x];
1348  if (++x == w) {
1349  x = 0;
1350  y++;
1351  }
1352  }
1353  }
1354  }
1355 }
1356 
1357 static int config_output(AVFilterLink *outlink)
1358 {
1359  AVFilterContext *ctx = outlink->src;
1360  LUT3DContext *lut3d = ctx->priv;
1361  int ret;
1362 
1363  ret = ff_framesync_init_dualinput(&lut3d->fs, ctx);
1364  if (ret < 0)
1365  return ret;
1366  outlink->w = ctx->inputs[0]->w;
1367  outlink->h = ctx->inputs[0]->h;
1368  outlink->time_base = ctx->inputs[0]->time_base;
1369  if ((ret = ff_framesync_configure(&lut3d->fs)) < 0)
1370  return ret;
1371  return 0;
1372 }
1373 
1374 static int activate(AVFilterContext *ctx)
1375 {
1376  LUT3DContext *s = ctx->priv;
1377  return ff_framesync_activate(&s->fs);
1378 }
1379 
1380 static int config_clut(AVFilterLink *inlink)
1381 {
1382  int size, level, w, h;
1383  AVFilterContext *ctx = inlink->dst;
1384  LUT3DContext *lut3d = ctx->priv;
1386 
1387  av_assert0(desc);
1388 
1389  lut3d->clut_bits = desc->comp[0].depth;
1390  lut3d->clut_planar = av_pix_fmt_count_planes(inlink->format) > 1;
1391  lut3d->clut_float = desc->flags & AV_PIX_FMT_FLAG_FLOAT;
1392 
1393  lut3d->clut_step = av_get_padded_bits_per_pixel(desc) >> 3;
1394  ff_fill_rgba_map(lut3d->clut_rgba_map, inlink->format);
1395 
1396  if (inlink->w > inlink->h)
1397  av_log(ctx, AV_LOG_INFO, "Padding on the right (%dpx) of the "
1398  "Hald CLUT will be ignored\n", inlink->w - inlink->h);
1399  else if (inlink->w < inlink->h)
1400  av_log(ctx, AV_LOG_INFO, "Padding at the bottom (%dpx) of the "
1401  "Hald CLUT will be ignored\n", inlink->h - inlink->w);
1402  lut3d->clut_width = w = h = FFMIN(inlink->w, inlink->h);
1403 
1404  for (level = 1; level*level*level < w; level++);
1405  size = level*level*level;
1406  if (size != w) {
1407  av_log(ctx, AV_LOG_WARNING, "The Hald CLUT width does not match the level\n");
1408  return AVERROR_INVALIDDATA;
1409  }
1410  av_assert0(w == h && w == size);
1411  level *= level;
1412  if (level > MAX_LEVEL) {
1413  const int max_clut_level = sqrt(MAX_LEVEL);
1414  const int max_clut_size = max_clut_level*max_clut_level*max_clut_level;
1415  av_log(ctx, AV_LOG_ERROR, "Too large Hald CLUT "
1416  "(maximum level is %d, or %dx%d CLUT)\n",
1417  max_clut_level, max_clut_size, max_clut_size);
1418  return AVERROR(EINVAL);
1419  }
1420 
1421  return allocate_3dlut(ctx, level, 0);
1422 }
1423 
1424 static int update_apply_clut(FFFrameSync *fs)
1425 {
1426  AVFilterContext *ctx = fs->parent;
1427  LUT3DContext *lut3d = ctx->priv;
1428  AVFilterLink *inlink = ctx->inputs[0];
1429  AVFrame *master, *second, *out;
1430  int ret;
1431 
1432  ret = ff_framesync_dualinput_get(fs, &master, &second);
1433  if (ret < 0)
1434  return ret;
1435  if (!second)
1436  return ff_filter_frame(ctx->outputs[0], master);
1437  if (lut3d->clut_float)
1438  update_clut_float(ctx->priv, second);
1439  else if (lut3d->clut_planar)
1440  update_clut_planar(ctx->priv, second);
1441  else
1442  update_clut_packed(ctx->priv, second);
1443  out = apply_lut(inlink, master);
1444  return ff_filter_frame(ctx->outputs[0], out);
1445 }
1446 
1447 static av_cold int haldclut_init(AVFilterContext *ctx)
1448 {
1449  LUT3DContext *lut3d = ctx->priv;
1450  lut3d->scale.r = lut3d->scale.g = lut3d->scale.b = 1.f;
1451  lut3d->fs.on_event = update_apply_clut;
1452  return 0;
1453 }
1454 
1455 static av_cold void haldclut_uninit(AVFilterContext *ctx)
1456 {
1457  LUT3DContext *lut3d = ctx->priv;
1458  ff_framesync_uninit(&lut3d->fs);
1459  av_freep(&lut3d->lut);
1460 }
1461 
1462 static const AVOption haldclut_options[] = {
1463  COMMON_OPTIONS
1464 };
1465 
1466 FRAMESYNC_DEFINE_CLASS(haldclut, LUT3DContext, fs);
1467 
1468 static const AVFilterPad haldclut_inputs[] = {
1469  {
1470  .name = "main",
1471  .type = AVMEDIA_TYPE_VIDEO,
1472  .config_props = config_input,
1473  },{
1474  .name = "clut",
1475  .type = AVMEDIA_TYPE_VIDEO,
1476  .config_props = config_clut,
1477  },
1478  { NULL }
1479 };
1480 
1481 static const AVFilterPad haldclut_outputs[] = {
1482  {
1483  .name = "default",
1484  .type = AVMEDIA_TYPE_VIDEO,
1485  .config_props = config_output,
1486  },
1487  { NULL }
1488 };
1489 
1491  .name = "haldclut",
1492  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a Hald CLUT."),
1493  .priv_size = sizeof(LUT3DContext),
1494  .preinit = haldclut_framesync_preinit,
1495  .init = haldclut_init,
1496  .uninit = haldclut_uninit,
1498  .activate = activate,
1499  .inputs = haldclut_inputs,
1500  .outputs = haldclut_outputs,
1501  .priv_class = &haldclut_class,
1503 };
1504 #endif
1505 
1506 #if CONFIG_LUT1D_FILTER
1507 
1508 enum interp_1d_mode {
1509  INTERPOLATE_1D_NEAREST,
1510  INTERPOLATE_1D_LINEAR,
1511  INTERPOLATE_1D_CUBIC,
1512  INTERPOLATE_1D_COSINE,
1513  INTERPOLATE_1D_SPLINE,
1514  NB_INTERP_1D_MODE
1515 };
1516 
1517 #define MAX_1D_LEVEL 65536
1518 
1519 typedef struct LUT1DContext {
1520  const AVClass *class;
1521  char *file;
1522  int interpolation; ///<interp_1d_mode
1523  struct rgbvec scale;
1524  uint8_t rgba_map[4];
1525  int step;
1526  float lut[3][MAX_1D_LEVEL];
1527  int lutsize;
1528  avfilter_action_func *interp;
1529 } LUT1DContext;
1530 
1531 #undef OFFSET
1532 #define OFFSET(x) offsetof(LUT1DContext, x)
1533 
1534 static void set_identity_matrix_1d(LUT1DContext *lut1d, int size)
1535 {
1536  const float c = 1. / (size - 1);
1537  int i;
1538 
1539  lut1d->lutsize = size;
1540  for (i = 0; i < size; i++) {
1541  lut1d->lut[0][i] = i * c;
1542  lut1d->lut[1][i] = i * c;
1543  lut1d->lut[2][i] = i * c;
1544  }
1545 }
1546 
1547 static int parse_cinespace_1d(AVFilterContext *ctx, FILE *f)
1548 {
1549  LUT1DContext *lut1d = ctx->priv;
1550  char line[MAX_LINE_SIZE];
1551  float in_min[3] = {0.0, 0.0, 0.0};
1552  float in_max[3] = {1.0, 1.0, 1.0};
1553  float out_min[3] = {0.0, 0.0, 0.0};
1554  float out_max[3] = {1.0, 1.0, 1.0};
1555  int inside_metadata = 0, size;
1556 
1557  NEXT_LINE(skip_line(line));
1558  if (strncmp(line, "CSPLUTV100", 10)) {
1559  av_log(ctx, AV_LOG_ERROR, "Not cineSpace LUT format\n");
1560  return AVERROR(EINVAL);
1561  }
1562 
1563  NEXT_LINE(skip_line(line));
1564  if (strncmp(line, "1D", 2)) {
1565  av_log(ctx, AV_LOG_ERROR, "Not 1D LUT format\n");
1566  return AVERROR(EINVAL);
1567  }
1568 
1569  while (1) {
1570  NEXT_LINE(skip_line(line));
1571 
1572  if (!strncmp(line, "BEGIN METADATA", 14)) {
1573  inside_metadata = 1;
1574  continue;
1575  }
1576  if (!strncmp(line, "END METADATA", 12)) {
1577  inside_metadata = 0;
1578  continue;
1579  }
1580  if (inside_metadata == 0) {
1581  for (int i = 0; i < 3; i++) {
1582  int npoints = strtol(line, NULL, 0);
1583 
1584  if (npoints != 2) {
1585  av_log(ctx, AV_LOG_ERROR, "Unsupported number of pre-lut points.\n");
1586  return AVERROR_PATCHWELCOME;
1587  }
1588 
1589  NEXT_LINE(skip_line(line));
1590  if (av_sscanf(line, "%f %f", &in_min[i], &in_max[i]) != 2)
1591  return AVERROR_INVALIDDATA;
1592  NEXT_LINE(skip_line(line));
1593  if (av_sscanf(line, "%f %f", &out_min[i], &out_max[i]) != 2)
1594  return AVERROR_INVALIDDATA;
1595  NEXT_LINE(skip_line(line));
1596  }
1597 
1598  size = strtol(line, NULL, 0);
1599 
1600  if (size < 2 || size > MAX_1D_LEVEL) {
1601  av_log(ctx, AV_LOG_ERROR, "Too large or invalid 1D LUT size\n");
1602  return AVERROR(EINVAL);
1603  }
1604 
1605  lut1d->lutsize = size;
1606 
1607  for (int i = 0; i < size; i++) {
1608  NEXT_LINE(skip_line(line));
1609  if (av_sscanf(line, "%f %f %f", &lut1d->lut[0][i], &lut1d->lut[1][i], &lut1d->lut[2][i]) != 3)
1610  return AVERROR_INVALIDDATA;
1611  lut1d->lut[0][i] *= out_max[0] - out_min[0];
1612  lut1d->lut[1][i] *= out_max[1] - out_min[1];
1613  lut1d->lut[2][i] *= out_max[2] - out_min[2];
1614  }
1615 
1616  break;
1617  }
1618  }
1619 
1620  lut1d->scale.r = av_clipf(1. / (in_max[0] - in_min[0]), 0.f, 1.f);
1621  lut1d->scale.g = av_clipf(1. / (in_max[1] - in_min[1]), 0.f, 1.f);
1622  lut1d->scale.b = av_clipf(1. / (in_max[2] - in_min[2]), 0.f, 1.f);
1623 
1624  return 0;
1625 }
1626 
1627 static int parse_cube_1d(AVFilterContext *ctx, FILE *f)
1628 {
1629  LUT1DContext *lut1d = ctx->priv;
1630  char line[MAX_LINE_SIZE];
1631  float min[3] = {0.0, 0.0, 0.0};
1632  float max[3] = {1.0, 1.0, 1.0};
1633 
1634  while (fgets(line, sizeof(line), f)) {
1635  if (!strncmp(line, "LUT_1D_SIZE", 11)) {
1636  const int size = strtol(line + 12, NULL, 0);
1637  int i;
1638 
1639  if (size < 2 || size > MAX_1D_LEVEL) {
1640  av_log(ctx, AV_LOG_ERROR, "Too large or invalid 1D LUT size\n");
1641  return AVERROR(EINVAL);
1642  }
1643  lut1d->lutsize = size;
1644  for (i = 0; i < size; i++) {
1645  do {
1646 try_again:
1647  NEXT_LINE(0);
1648  if (!strncmp(line, "DOMAIN_", 7)) {
1649  float *vals = NULL;
1650  if (!strncmp(line + 7, "MIN ", 4)) vals = min;
1651  else if (!strncmp(line + 7, "MAX ", 4)) vals = max;
1652  if (!vals)
1653  return AVERROR_INVALIDDATA;
1654  av_sscanf(line + 11, "%f %f %f", vals, vals + 1, vals + 2);
1655  av_log(ctx, AV_LOG_DEBUG, "min: %f %f %f | max: %f %f %f\n",
1656  min[0], min[1], min[2], max[0], max[1], max[2]);
1657  goto try_again;
1658  } else if (!strncmp(line, "LUT_1D_INPUT_RANGE ", 19)) {
1659  av_sscanf(line + 19, "%f %f", min, max);
1660  min[1] = min[2] = min[0];
1661  max[1] = max[2] = max[0];
1662  goto try_again;
1663  } else if (!strncmp(line, "TITLE", 5)) {
1664  goto try_again;
1665  }
1666  } while (skip_line(line));
1667  if (av_sscanf(line, "%f %f %f", &lut1d->lut[0][i], &lut1d->lut[1][i], &lut1d->lut[2][i]) != 3)
1668  return AVERROR_INVALIDDATA;
1669  }
1670  break;
1671  }
1672  }
1673 
1674  lut1d->scale.r = av_clipf(1. / (max[0] - min[0]), 0.f, 1.f);
1675  lut1d->scale.g = av_clipf(1. / (max[1] - min[1]), 0.f, 1.f);
1676  lut1d->scale.b = av_clipf(1. / (max[2] - min[2]), 0.f, 1.f);
1677 
1678  return 0;
1679 }
1680 
1681 static const AVOption lut1d_options[] = {
1682  { "file", "set 1D LUT file name", OFFSET(file), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
1683  { "interp", "select interpolation mode", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=INTERPOLATE_1D_LINEAR}, 0, NB_INTERP_1D_MODE-1, FLAGS, "interp_mode" },
1684  { "nearest", "use values from the nearest defined points", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_NEAREST}, INT_MIN, INT_MAX, FLAGS, "interp_mode" },
1685  { "linear", "use values from the linear interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_LINEAR}, INT_MIN, INT_MAX, FLAGS, "interp_mode" },
1686  { "cosine", "use values from the cosine interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_COSINE}, INT_MIN, INT_MAX, FLAGS, "interp_mode" },
1687  { "cubic", "use values from the cubic interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_CUBIC}, INT_MIN, INT_MAX, FLAGS, "interp_mode" },
1688  { "spline", "use values from the spline interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_SPLINE}, INT_MIN, INT_MAX, FLAGS, "interp_mode" },
1689  { NULL }
1690 };
1691 
1692 AVFILTER_DEFINE_CLASS(lut1d);
1693 
1694 static inline float interp_1d_nearest(const LUT1DContext *lut1d,
1695  int idx, const float s)
1696 {
1697  return lut1d->lut[idx][NEAR(s)];
1698 }
1699 
1700 #define NEXT1D(x) (FFMIN((int)(x) + 1, lut1d->lutsize - 1))
1701 
1702 static inline float interp_1d_linear(const LUT1DContext *lut1d,
1703  int idx, const float s)
1704 {
1705  const int prev = PREV(s);
1706  const int next = NEXT1D(s);
1707  const float d = s - prev;
1708  const float p = lut1d->lut[idx][prev];
1709  const float n = lut1d->lut[idx][next];
1710 
1711  return lerpf(p, n, d);
1712 }
1713 
1714 static inline float interp_1d_cosine(const LUT1DContext *lut1d,
1715  int idx, const float s)
1716 {
1717  const int prev = PREV(s);
1718  const int next = NEXT1D(s);
1719  const float d = s - prev;
1720  const float p = lut1d->lut[idx][prev];
1721  const float n = lut1d->lut[idx][next];
1722  const float m = (1.f - cosf(d * M_PI)) * .5f;
1723 
1724  return lerpf(p, n, m);
1725 }
1726 
1727 static inline float interp_1d_cubic(const LUT1DContext *lut1d,
1728  int idx, const float s)
1729 {
1730  const int prev = PREV(s);
1731  const int next = NEXT1D(s);
1732  const float mu = s - prev;
1733  float a0, a1, a2, a3, mu2;
1734 
1735  float y0 = lut1d->lut[idx][FFMAX(prev - 1, 0)];
1736  float y1 = lut1d->lut[idx][prev];
1737  float y2 = lut1d->lut[idx][next];
1738  float y3 = lut1d->lut[idx][FFMIN(next + 1, lut1d->lutsize - 1)];
1739 
1740 
1741  mu2 = mu * mu;
1742  a0 = y3 - y2 - y0 + y1;
1743  a1 = y0 - y1 - a0;
1744  a2 = y2 - y0;
1745  a3 = y1;
1746 
1747  return a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3;
1748 }
1749 
1750 static inline float interp_1d_spline(const LUT1DContext *lut1d,
1751  int idx, const float s)
1752 {
1753  const int prev = PREV(s);
1754  const int next = NEXT1D(s);
1755  const float x = s - prev;
1756  float c0, c1, c2, c3;
1757 
1758  float y0 = lut1d->lut[idx][FFMAX(prev - 1, 0)];
1759  float y1 = lut1d->lut[idx][prev];
1760  float y2 = lut1d->lut[idx][next];
1761  float y3 = lut1d->lut[idx][FFMIN(next + 1, lut1d->lutsize - 1)];
1762 
1763  c0 = y1;
1764  c1 = .5f * (y2 - y0);
1765  c2 = y0 - 2.5f * y1 + 2.f * y2 - .5f * y3;
1766  c3 = .5f * (y3 - y0) + 1.5f * (y1 - y2);
1767 
1768  return ((c3 * x + c2) * x + c1) * x + c0;
1769 }
1770 
1771 #define DEFINE_INTERP_FUNC_PLANAR_1D(name, nbits, depth) \
1772 static int interp_1d_##nbits##_##name##_p##depth(AVFilterContext *ctx, \
1773  void *arg, int jobnr, \
1774  int nb_jobs) \
1775 { \
1776  int x, y; \
1777  const LUT1DContext *lut1d = ctx->priv; \
1778  const ThreadData *td = arg; \
1779  const AVFrame *in = td->in; \
1780  const AVFrame *out = td->out; \
1781  const int direct = out == in; \
1782  const int slice_start = (in->height * jobnr ) / nb_jobs; \
1783  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
1784  uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
1785  uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
1786  uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
1787  uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
1788  const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
1789  const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
1790  const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
1791  const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
1792  const float factor = (1 << depth) - 1; \
1793  const float scale_r = (lut1d->scale.r / factor) * (lut1d->lutsize - 1); \
1794  const float scale_g = (lut1d->scale.g / factor) * (lut1d->lutsize - 1); \
1795  const float scale_b = (lut1d->scale.b / factor) * (lut1d->lutsize - 1); \
1796  \
1797  for (y = slice_start; y < slice_end; y++) { \
1798  uint##nbits##_t *dstg = (uint##nbits##_t *)grow; \
1799  uint##nbits##_t *dstb = (uint##nbits##_t *)brow; \
1800  uint##nbits##_t *dstr = (uint##nbits##_t *)rrow; \
1801  uint##nbits##_t *dsta = (uint##nbits##_t *)arow; \
1802  const uint##nbits##_t *srcg = (const uint##nbits##_t *)srcgrow; \
1803  const uint##nbits##_t *srcb = (const uint##nbits##_t *)srcbrow; \
1804  const uint##nbits##_t *srcr = (const uint##nbits##_t *)srcrrow; \
1805  const uint##nbits##_t *srca = (const uint##nbits##_t *)srcarow; \
1806  for (x = 0; x < in->width; x++) { \
1807  float r = srcr[x] * scale_r; \
1808  float g = srcg[x] * scale_g; \
1809  float b = srcb[x] * scale_b; \
1810  r = interp_1d_##name(lut1d, 0, r); \
1811  g = interp_1d_##name(lut1d, 1, g); \
1812  b = interp_1d_##name(lut1d, 2, b); \
1813  dstr[x] = av_clip_uintp2(r * factor, depth); \
1814  dstg[x] = av_clip_uintp2(g * factor, depth); \
1815  dstb[x] = av_clip_uintp2(b * factor, depth); \
1816  if (!direct && in->linesize[3]) \
1817  dsta[x] = srca[x]; \
1818  } \
1819  grow += out->linesize[0]; \
1820  brow += out->linesize[1]; \
1821  rrow += out->linesize[2]; \
1822  arow += out->linesize[3]; \
1823  srcgrow += in->linesize[0]; \
1824  srcbrow += in->linesize[1]; \
1825  srcrrow += in->linesize[2]; \
1826  srcarow += in->linesize[3]; \
1827  } \
1828  return 0; \
1829 }
1830 
1831 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 8, 8)
1832 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 8, 8)
1833 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 8, 8)
1834 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 8, 8)
1835 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 8, 8)
1836 
1837 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 9)
1838 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 9)
1839 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 9)
1840 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 9)
1841 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 9)
1842 
1843 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 10)
1844 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 10)
1845 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 10)
1846 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 10)
1847 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 10)
1848 
1849 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 12)
1850 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 12)
1851 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 12)
1852 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 12)
1853 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 12)
1854 
1855 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 14)
1856 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 14)
1857 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 14)
1858 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 14)
1859 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 14)
1860 
1861 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 16)
1862 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 16)
1863 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 16)
1864 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 16)
1865 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 16)
1866 
1867 #define DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(name, depth) \
1868 static int interp_1d_##name##_pf##depth(AVFilterContext *ctx, \
1869  void *arg, int jobnr, \
1870  int nb_jobs) \
1871 { \
1872  int x, y; \
1873  const LUT1DContext *lut1d = ctx->priv; \
1874  const ThreadData *td = arg; \
1875  const AVFrame *in = td->in; \
1876  const AVFrame *out = td->out; \
1877  const int direct = out == in; \
1878  const int slice_start = (in->height * jobnr ) / nb_jobs; \
1879  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
1880  uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
1881  uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
1882  uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
1883  uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
1884  const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
1885  const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
1886  const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
1887  const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
1888  const float lutsize = lut1d->lutsize - 1; \
1889  const float scale_r = lut1d->scale.r * lutsize; \
1890  const float scale_g = lut1d->scale.g * lutsize; \
1891  const float scale_b = lut1d->scale.b * lutsize; \
1892  \
1893  for (y = slice_start; y < slice_end; y++) { \
1894  float *dstg = (float *)grow; \
1895  float *dstb = (float *)brow; \
1896  float *dstr = (float *)rrow; \
1897  float *dsta = (float *)arow; \
1898  const float *srcg = (const float *)srcgrow; \
1899  const float *srcb = (const float *)srcbrow; \
1900  const float *srcr = (const float *)srcrrow; \
1901  const float *srca = (const float *)srcarow; \
1902  for (x = 0; x < in->width; x++) { \
1903  float r = av_clipf(sanitizef(srcr[x]) * scale_r, 0.0f, lutsize); \
1904  float g = av_clipf(sanitizef(srcg[x]) * scale_g, 0.0f, lutsize); \
1905  float b = av_clipf(sanitizef(srcb[x]) * scale_b, 0.0f, lutsize); \
1906  r = interp_1d_##name(lut1d, 0, r); \
1907  g = interp_1d_##name(lut1d, 1, g); \
1908  b = interp_1d_##name(lut1d, 2, b); \
1909  dstr[x] = r; \
1910  dstg[x] = g; \
1911  dstb[x] = b; \
1912  if (!direct && in->linesize[3]) \
1913  dsta[x] = srca[x]; \
1914  } \
1915  grow += out->linesize[0]; \
1916  brow += out->linesize[1]; \
1917  rrow += out->linesize[2]; \
1918  arow += out->linesize[3]; \
1919  srcgrow += in->linesize[0]; \
1920  srcbrow += in->linesize[1]; \
1921  srcrrow += in->linesize[2]; \
1922  srcarow += in->linesize[3]; \
1923  } \
1924  return 0; \
1925 }
1926 
1927 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(nearest, 32)
1928 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(linear, 32)
1929 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(cosine, 32)
1930 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(cubic, 32)
1931 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(spline, 32)
1932 
1933 #define DEFINE_INTERP_FUNC_1D(name, nbits) \
1934 static int interp_1d_##nbits##_##name(AVFilterContext *ctx, void *arg, \
1935  int jobnr, int nb_jobs) \
1936 { \
1937  int x, y; \
1938  const LUT1DContext *lut1d = ctx->priv; \
1939  const ThreadData *td = arg; \
1940  const AVFrame *in = td->in; \
1941  const AVFrame *out = td->out; \
1942  const int direct = out == in; \
1943  const int step = lut1d->step; \
1944  const uint8_t r = lut1d->rgba_map[R]; \
1945  const uint8_t g = lut1d->rgba_map[G]; \
1946  const uint8_t b = lut1d->rgba_map[B]; \
1947  const uint8_t a = lut1d->rgba_map[A]; \
1948  const int slice_start = (in->height * jobnr ) / nb_jobs; \
1949  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
1950  uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \
1951  const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \
1952  const float factor = (1 << nbits) - 1; \
1953  const float scale_r = (lut1d->scale.r / factor) * (lut1d->lutsize - 1); \
1954  const float scale_g = (lut1d->scale.g / factor) * (lut1d->lutsize - 1); \
1955  const float scale_b = (lut1d->scale.b / factor) * (lut1d->lutsize - 1); \
1956  \
1957  for (y = slice_start; y < slice_end; y++) { \
1958  uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \
1959  const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \
1960  for (x = 0; x < in->width * step; x += step) { \
1961  float rr = src[x + r] * scale_r; \
1962  float gg = src[x + g] * scale_g; \
1963  float bb = src[x + b] * scale_b; \
1964  rr = interp_1d_##name(lut1d, 0, rr); \
1965  gg = interp_1d_##name(lut1d, 1, gg); \
1966  bb = interp_1d_##name(lut1d, 2, bb); \
1967  dst[x + r] = av_clip_uint##nbits(rr * factor); \
1968  dst[x + g] = av_clip_uint##nbits(gg * factor); \
1969  dst[x + b] = av_clip_uint##nbits(bb * factor); \
1970  if (!direct && step == 4) \
1971  dst[x + a] = src[x + a]; \
1972  } \
1973  dstrow += out->linesize[0]; \
1974  srcrow += in ->linesize[0]; \
1975  } \
1976  return 0; \
1977 }
1978 
1979 DEFINE_INTERP_FUNC_1D(nearest, 8)
1980 DEFINE_INTERP_FUNC_1D(linear, 8)
1981 DEFINE_INTERP_FUNC_1D(cosine, 8)
1982 DEFINE_INTERP_FUNC_1D(cubic, 8)
1983 DEFINE_INTERP_FUNC_1D(spline, 8)
1984 
1985 DEFINE_INTERP_FUNC_1D(nearest, 16)
1986 DEFINE_INTERP_FUNC_1D(linear, 16)
1987 DEFINE_INTERP_FUNC_1D(cosine, 16)
1988 DEFINE_INTERP_FUNC_1D(cubic, 16)
1989 DEFINE_INTERP_FUNC_1D(spline, 16)
1990 
1991 static int config_input_1d(AVFilterLink *inlink)
1992 {
1993  int depth, is16bit, isfloat, planar;
1994  LUT1DContext *lut1d = inlink->dst->priv;
1996 
1997  depth = desc->comp[0].depth;
1998  is16bit = desc->comp[0].depth > 8;
1999  planar = desc->flags & AV_PIX_FMT_FLAG_PLANAR;
2000  isfloat = desc->flags & AV_PIX_FMT_FLAG_FLOAT;
2001  ff_fill_rgba_map(lut1d->rgba_map, inlink->format);
2002  lut1d->step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit);
2003 
2004 #define SET_FUNC_1D(name) do { \
2005  if (planar && !isfloat) { \
2006  switch (depth) { \
2007  case 8: lut1d->interp = interp_1d_8_##name##_p8; break; \
2008  case 9: lut1d->interp = interp_1d_16_##name##_p9; break; \
2009  case 10: lut1d->interp = interp_1d_16_##name##_p10; break; \
2010  case 12: lut1d->interp = interp_1d_16_##name##_p12; break; \
2011  case 14: lut1d->interp = interp_1d_16_##name##_p14; break; \
2012  case 16: lut1d->interp = interp_1d_16_##name##_p16; break; \
2013  } \
2014  } else if (isfloat) { lut1d->interp = interp_1d_##name##_pf32; \
2015  } else if (is16bit) { lut1d->interp = interp_1d_16_##name; \
2016  } else { lut1d->interp = interp_1d_8_##name; } \
2017 } while (0)
2018 
2019  switch (lut1d->interpolation) {
2020  case INTERPOLATE_1D_NEAREST: SET_FUNC_1D(nearest); break;
2021  case INTERPOLATE_1D_LINEAR: SET_FUNC_1D(linear); break;
2022  case INTERPOLATE_1D_COSINE: SET_FUNC_1D(cosine); break;
2023  case INTERPOLATE_1D_CUBIC: SET_FUNC_1D(cubic); break;
2024  case INTERPOLATE_1D_SPLINE: SET_FUNC_1D(spline); break;
2025  default:
2026  av_assert0(0);
2027  }
2028 
2029  return 0;
2030 }
2031 
2032 static av_cold int lut1d_init(AVFilterContext *ctx)
2033 {
2034  int ret;
2035  FILE *f;
2036  const char *ext;
2037  LUT1DContext *lut1d = ctx->priv;
2038 
2039  lut1d->scale.r = lut1d->scale.g = lut1d->scale.b = 1.f;
2040 
2041  if (!lut1d->file) {
2042  set_identity_matrix_1d(lut1d, 32);
2043  return 0;
2044  }
2045 
2046  f = av_fopen_utf8(lut1d->file, "r");
2047  if (!f) {
2048  ret = AVERROR(errno);
2049  av_log(ctx, AV_LOG_ERROR, "%s: %s\n", lut1d->file, av_err2str(ret));
2050  return ret;
2051  }
2052 
2053  ext = strrchr(lut1d->file, '.');
2054  if (!ext) {
2055  av_log(ctx, AV_LOG_ERROR, "Unable to guess the format from the extension\n");
2056  ret = AVERROR_INVALIDDATA;
2057  goto end;
2058  }
2059  ext++;
2060 
2061  if (!av_strcasecmp(ext, "cube") || !av_strcasecmp(ext, "1dlut")) {
2062  ret = parse_cube_1d(ctx, f);
2063  } else if (!av_strcasecmp(ext, "csp")) {
2064  ret = parse_cinespace_1d(ctx, f);
2065  } else {
2066  av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext);
2067  ret = AVERROR(EINVAL);
2068  }
2069 
2070  if (!ret && !lut1d->lutsize) {
2071  av_log(ctx, AV_LOG_ERROR, "1D LUT is empty\n");
2072  ret = AVERROR_INVALIDDATA;
2073  }
2074 
2075 end:
2076  fclose(f);
2077  return ret;
2078 }
2079 
2080 static AVFrame *apply_1d_lut(AVFilterLink *inlink, AVFrame *in)
2081 {
2082  AVFilterContext *ctx = inlink->dst;
2083  LUT1DContext *lut1d = ctx->priv;
2084  AVFilterLink *outlink = inlink->dst->outputs[0];
2085  AVFrame *out;
2086  ThreadData td;
2087 
2088  if (av_frame_is_writable(in)) {
2089  out = in;
2090  } else {
2091  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
2092  if (!out) {
2093  av_frame_free(&in);
2094  return NULL;
2095  }
2096  av_frame_copy_props(out, in);
2097  }
2098 
2099  td.in = in;
2100  td.out = out;
2101  ctx->internal->execute(ctx, lut1d->interp, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
2102 
2103  if (out != in)
2104  av_frame_free(&in);
2105 
2106  return out;
2107 }
2108 
2109 static int filter_frame_1d(AVFilterLink *inlink, AVFrame *in)
2110 {
2111  AVFilterLink *outlink = inlink->dst->outputs[0];
2112  AVFrame *out = apply_1d_lut(inlink, in);
2113  if (!out)
2114  return AVERROR(ENOMEM);
2115  return ff_filter_frame(outlink, out);
2116 }
2117 
2118 static const AVFilterPad lut1d_inputs[] = {
2119  {
2120  .name = "default",
2121  .type = AVMEDIA_TYPE_VIDEO,
2122  .filter_frame = filter_frame_1d,
2123  .config_props = config_input_1d,
2124  },
2125  { NULL }
2126 };
2127 
2128 static const AVFilterPad lut1d_outputs[] = {
2129  {
2130  .name = "default",
2131  .type = AVMEDIA_TYPE_VIDEO,
2132  },
2133  { NULL }
2134 };
2135 
2137  .name = "lut1d",
2138  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a 1D LUT."),
2139  .priv_size = sizeof(LUT1DContext),
2140  .init = lut1d_init,
2142  .inputs = lut1d_inputs,
2143  .outputs = lut1d_outputs,
2144  .priv_class = &lut1d_class,
2146 };
2147 #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:1057
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:314
#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
const char * desc
Definition: libsvtav1.c:79
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
uint8_t pi<< 24) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_U8,(uint64_t)((*(const uint8_t *) pi-0x80U))<< 56) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8,(*(const uint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8,(*(const uint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16,(*(const int16_t *) pi >>8)+0x80) CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S16,*(const int16_t *) pi *(1<< 16)) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S16,(uint64_t)(*(const int16_t *) pi)<< 48) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16,*(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16,*(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32,(*(const int32_t *) pi >>24)+0x80) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S32,(uint64_t)(*(const int32_t *) pi)<< 32) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32,*(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32,*(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S64,(*(const int64_t *) pi >>56)+0x80) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S64,*(const int64_t *) pi *(1.0f/(UINT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S64,*(const int64_t *) pi *(1.0/(UINT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_FLT, llrintf(*(const float *) pi *(UINT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31)))) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_DBL, llrint(*(const double *) pi *(UINT64_C(1)<< 63)))#define FMT_PAIR_FUNC(out, in) static conv_func_type *const fmt_pair_to_conv_functions[AV_SAMPLE_FMT_NB *AV_SAMPLE_FMT_NB]={FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64),};static void cpy1(uint8_t **dst, const uint8_t **src, int len){memcpy(*dst,*src, len);}static void cpy2(uint8_t **dst, const uint8_t **src, int len){memcpy(*dst,*src, 2 *len);}static void cpy4(uint8_t **dst, const uint8_t **src, int len){memcpy(*dst,*src, 4 *len);}static void cpy8(uint8_t **dst, const uint8_t **src, int len){memcpy(*dst,*src, 8 *len);}AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, const int *ch_map, int flags){AudioConvert *ctx;conv_func_type *f=fmt_pair_to_conv_functions[av_get_packed_sample_fmt(out_fmt)+AV_SAMPLE_FMT_NB *av_get_packed_sample_fmt(in_fmt)];if(!f) return NULL;ctx=av_mallocz(sizeof(*ctx));if(!ctx) return NULL;if(channels==1){in_fmt=av_get_planar_sample_fmt(in_fmt);out_fmt=av_get_planar_sample_fmt(out_fmt);}ctx->channels=channels;ctx->conv_f=f;ctx->ch_map=ch_map;if(in_fmt==AV_SAMPLE_FMT_U8||in_fmt==AV_SAMPLE_FMT_U8P) memset(ctx->silence, 0x80, sizeof(ctx->silence));if(out_fmt==in_fmt &&!ch_map){switch(av_get_bytes_per_sample(in_fmt)){case 1:ctx->simd_f=cpy1;break;case 2:ctx->simd_f=cpy2;break;case 4:ctx->simd_f=cpy4;break;case 8:ctx->simd_f=cpy8;break;}}if(HAVE_X86ASM &&1) swri_audio_convert_init_x86(ctx, out_fmt, in_fmt, channels);if(ARCH_ARM) swri_audio_convert_init_arm(ctx, out_fmt, in_fmt, channels);if(ARCH_AARCH64) swri_audio_convert_init_aarch64(ctx, out_fmt, in_fmt, channels);return ctx;}void swri_audio_convert_free(AudioConvert **ctx){av_freep(ctx);}int swri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, int len){int ch;int off=0;const int os=(out->planar?1:out->ch_count)*out->bps;unsigned misaligned=0;av_assert0(ctx->channels==out->ch_count);if(ctx->in_simd_align_mask){int planes=in->planar?in->ch_count:1;unsigned m=0;for(ch=0;ch< planes;ch++) m|=(intptr_t) in->ch[ch];misaligned|=m &ctx->in_simd_align_mask;}if(ctx->out_simd_align_mask){int planes=out->planar?out->ch_count:1;unsigned m=0;for(ch=0;ch< planes;ch++) m|=(intptr_t) out->ch[ch];misaligned|=m &ctx->out_simd_align_mask;}if(ctx->simd_f &&!ctx->ch_map &&!misaligned){off=len &~15;av_assert1(off >=0);av_assert1(off<=len);av_assert2(ctx->channels==SWR_CH_MAX||!in->ch[ctx->channels]);if(off >0){if(out->planar==in->planar){int planes=out->planar?out->ch_count:1;for(ch=0;ch< planes;ch++){ctx->simd_f(out->ch+ch,(const uint8_t **) in->ch+ch, off *(out-> planar
Definition: audioconvert.c:56
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:227
#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:287
float min[3]
Definition: vf_lut3d.c:66
static int set_identity_matrix(AVFilterContext *ctx, int size)
Definition: vf_lut3d.c:1007
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:398
#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
Some filters support a generic "enable" expression option that can be used to enable or disable a fil...
Definition: avfilter.h:126
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:349
#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:190
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:92
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:51
#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:398
#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:588
#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:356
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:117
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:215
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:215
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:398
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:1096
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:838
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:594
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:345
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:81
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:145
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:149
#define AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
Same as AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, except that the filter will have its filter_frame() c...
Definition: avfilter.h:134
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:353
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:300
#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:381
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:328
uint8_t level
Definition: svq3.c:205
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:52
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:1125
avfilter_execute_func * execute
Definition: internal.h:136
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:288
float scale[3]
Definition: vf_lut3d.c:68
A list of supported formats for one end of a filter link.
Definition: formats.h:65
An instance of a filter.
Definition: avfilter.h:341
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:1032
AVFrame * in
Definition: af_adenorm.c:223
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:658
int i
Definition: input.c:407
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
static int config_output(AVFilterLink *outlink)
Definition: af_adenorm.c:185
avfilter_action_func * interp
Definition: vf_lut3d.c:78