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 "libavutil/opt.h"
28 #include "libavutil/file.h"
29 #include "libavutil/intreadwrite.h"
30 #include "libavutil/avassert.h"
31 #include "libavutil/pixdesc.h"
32 #include "libavutil/avstring.h"
33 #include "avfilter.h"
34 #include "drawutils.h"
35 #include "formats.h"
36 #include "framesync.h"
37 #include "internal.h"
38 #include "video.h"
39 
40 #define R 0
41 #define G 1
42 #define B 2
43 #define A 3
44 
50 };
51 
52 struct rgbvec {
53  float r, g, b;
54 };
55 
56 /* 3D LUT don't often go up to level 32, but it is common to have a Hald CLUT
57  * of 512x512 (64x64x64) */
58 #define MAX_LEVEL 256
59 
60 typedef struct LUT3DContext {
61  const AVClass *class;
62  int interpolation; ///<interp_mode
63  char *file;
64  uint8_t rgba_map[4];
65  int step;
67  struct rgbvec scale;
68  struct rgbvec *lut;
69  int lutsize;
70  int lutsize2;
71 #if CONFIG_HALDCLUT_FILTER
72  uint8_t clut_rgba_map[4];
73  int clut_step;
74  int clut_bits;
75  int clut_planar;
76  int clut_width;
78 #endif
79 } LUT3DContext;
80 
81 typedef struct ThreadData {
82  AVFrame *in, *out;
83 } ThreadData;
84 
85 #define OFFSET(x) offsetof(LUT3DContext, x)
86 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
87 #define COMMON_OPTIONS \
88  { "interp", "select interpolation mode", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=INTERPOLATE_TETRAHEDRAL}, 0, NB_INTERP_MODE-1, FLAGS, "interp_mode" }, \
89  { "nearest", "use values from the nearest defined points", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_NEAREST}, INT_MIN, INT_MAX, FLAGS, "interp_mode" }, \
90  { "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" }, \
91  { "tetrahedral", "interpolate values using a tetrahedron", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_TETRAHEDRAL}, INT_MIN, INT_MAX, FLAGS, "interp_mode" }, \
92  { NULL }
93 
94 static inline float lerpf(float v0, float v1, float f)
95 {
96  return v0 + (v1 - v0) * f;
97 }
98 
99 static inline struct rgbvec lerp(const struct rgbvec *v0, const struct rgbvec *v1, float f)
100 {
101  struct rgbvec v = {
102  lerpf(v0->r, v1->r, f), lerpf(v0->g, v1->g, f), lerpf(v0->b, v1->b, f)
103  };
104  return v;
105 }
106 
107 #define NEAR(x) ((int)((x) + .5))
108 #define PREV(x) ((int)(x))
109 #define NEXT(x) (FFMIN((int)(x) + 1, lut3d->lutsize - 1))
110 
111 /**
112  * Get the nearest defined point
113  */
114 static inline struct rgbvec interp_nearest(const LUT3DContext *lut3d,
115  const struct rgbvec *s)
116 {
117  return lut3d->lut[NEAR(s->r) * lut3d->lutsize2 + NEAR(s->g) * lut3d->lutsize + NEAR(s->b)];
118 }
119 
120 /**
121  * Interpolate using the 8 vertices of a cube
122  * @see https://en.wikipedia.org/wiki/Trilinear_interpolation
123  */
124 static inline struct rgbvec interp_trilinear(const LUT3DContext *lut3d,
125  const struct rgbvec *s)
126 {
127  const int lutsize2 = lut3d->lutsize2;
128  const int lutsize = lut3d->lutsize;
129  const int prev[] = {PREV(s->r), PREV(s->g), PREV(s->b)};
130  const int next[] = {NEXT(s->r), NEXT(s->g), NEXT(s->b)};
131  const struct rgbvec d = {s->r - prev[0], s->g - prev[1], s->b - prev[2]};
132  const struct rgbvec c000 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + prev[2]];
133  const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
134  const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
135  const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
136  const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
137  const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
138  const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
139  const struct rgbvec c111 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + next[2]];
140  const struct rgbvec c00 = lerp(&c000, &c100, d.r);
141  const struct rgbvec c10 = lerp(&c010, &c110, d.r);
142  const struct rgbvec c01 = lerp(&c001, &c101, d.r);
143  const struct rgbvec c11 = lerp(&c011, &c111, d.r);
144  const struct rgbvec c0 = lerp(&c00, &c10, d.g);
145  const struct rgbvec c1 = lerp(&c01, &c11, d.g);
146  const struct rgbvec c = lerp(&c0, &c1, d.b);
147  return c;
148 }
149 
150 /**
151  * Tetrahedral interpolation. Based on code found in Truelight Software Library paper.
152  * @see http://www.filmlight.ltd.uk/pdf/whitepapers/FL-TL-TN-0057-SoftwareLib.pdf
153  */
154 static inline struct rgbvec interp_tetrahedral(const LUT3DContext *lut3d,
155  const struct rgbvec *s)
156 {
157  const int lutsize2 = lut3d->lutsize2;
158  const int lutsize = lut3d->lutsize;
159  const int prev[] = {PREV(s->r), PREV(s->g), PREV(s->b)};
160  const int next[] = {NEXT(s->r), NEXT(s->g), NEXT(s->b)};
161  const struct rgbvec d = {s->r - prev[0], s->g - prev[1], s->b - prev[2]};
162  const struct rgbvec c000 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + prev[2]];
163  const struct rgbvec c111 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + next[2]];
164  struct rgbvec c;
165  if (d.r > d.g) {
166  if (d.g > d.b) {
167  const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
168  const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
169  c.r = (1-d.r) * c000.r + (d.r-d.g) * c100.r + (d.g-d.b) * c110.r + (d.b) * c111.r;
170  c.g = (1-d.r) * c000.g + (d.r-d.g) * c100.g + (d.g-d.b) * c110.g + (d.b) * c111.g;
171  c.b = (1-d.r) * c000.b + (d.r-d.g) * c100.b + (d.g-d.b) * c110.b + (d.b) * c111.b;
172  } else if (d.r > d.b) {
173  const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
174  const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
175  c.r = (1-d.r) * c000.r + (d.r-d.b) * c100.r + (d.b-d.g) * c101.r + (d.g) * c111.r;
176  c.g = (1-d.r) * c000.g + (d.r-d.b) * c100.g + (d.b-d.g) * c101.g + (d.g) * c111.g;
177  c.b = (1-d.r) * c000.b + (d.r-d.b) * c100.b + (d.b-d.g) * c101.b + (d.g) * c111.b;
178  } else {
179  const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
180  const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
181  c.r = (1-d.b) * c000.r + (d.b-d.r) * c001.r + (d.r-d.g) * c101.r + (d.g) * c111.r;
182  c.g = (1-d.b) * c000.g + (d.b-d.r) * c001.g + (d.r-d.g) * c101.g + (d.g) * c111.g;
183  c.b = (1-d.b) * c000.b + (d.b-d.r) * c001.b + (d.r-d.g) * c101.b + (d.g) * c111.b;
184  }
185  } else {
186  if (d.b > d.g) {
187  const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
188  const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
189  c.r = (1-d.b) * c000.r + (d.b-d.g) * c001.r + (d.g-d.r) * c011.r + (d.r) * c111.r;
190  c.g = (1-d.b) * c000.g + (d.b-d.g) * c001.g + (d.g-d.r) * c011.g + (d.r) * c111.g;
191  c.b = (1-d.b) * c000.b + (d.b-d.g) * c001.b + (d.g-d.r) * c011.b + (d.r) * c111.b;
192  } else if (d.b > d.r) {
193  const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
194  const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
195  c.r = (1-d.g) * c000.r + (d.g-d.b) * c010.r + (d.b-d.r) * c011.r + (d.r) * c111.r;
196  c.g = (1-d.g) * c000.g + (d.g-d.b) * c010.g + (d.b-d.r) * c011.g + (d.r) * c111.g;
197  c.b = (1-d.g) * c000.b + (d.g-d.b) * c010.b + (d.b-d.r) * c011.b + (d.r) * c111.b;
198  } else {
199  const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
200  const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
201  c.r = (1-d.g) * c000.r + (d.g-d.r) * c010.r + (d.r-d.b) * c110.r + (d.b) * c111.r;
202  c.g = (1-d.g) * c000.g + (d.g-d.r) * c010.g + (d.r-d.b) * c110.g + (d.b) * c111.g;
203  c.b = (1-d.g) * c000.b + (d.g-d.r) * c010.b + (d.r-d.b) * c110.b + (d.b) * c111.b;
204  }
205  }
206  return c;
207 }
208 
209 #define DEFINE_INTERP_FUNC_PLANAR(name, nbits, depth) \
210 static int interp_##nbits##_##name##_p##depth(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
211 { \
212  int x, y; \
213  const LUT3DContext *lut3d = ctx->priv; \
214  const ThreadData *td = arg; \
215  const AVFrame *in = td->in; \
216  const AVFrame *out = td->out; \
217  const int direct = out == in; \
218  const int slice_start = (in->height * jobnr ) / nb_jobs; \
219  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
220  uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
221  uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
222  uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
223  uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
224  const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
225  const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
226  const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
227  const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
228  const float scale_r = (lut3d->scale.r / ((1<<depth) - 1)) * (lut3d->lutsize - 1); \
229  const float scale_g = (lut3d->scale.g / ((1<<depth) - 1)) * (lut3d->lutsize - 1); \
230  const float scale_b = (lut3d->scale.b / ((1<<depth) - 1)) * (lut3d->lutsize - 1); \
231  \
232  for (y = slice_start; y < slice_end; y++) { \
233  uint##nbits##_t *dstg = (uint##nbits##_t *)grow; \
234  uint##nbits##_t *dstb = (uint##nbits##_t *)brow; \
235  uint##nbits##_t *dstr = (uint##nbits##_t *)rrow; \
236  uint##nbits##_t *dsta = (uint##nbits##_t *)arow; \
237  const uint##nbits##_t *srcg = (const uint##nbits##_t *)srcgrow; \
238  const uint##nbits##_t *srcb = (const uint##nbits##_t *)srcbrow; \
239  const uint##nbits##_t *srcr = (const uint##nbits##_t *)srcrrow; \
240  const uint##nbits##_t *srca = (const uint##nbits##_t *)srcarow; \
241  for (x = 0; x < in->width; x++) { \
242  const struct rgbvec scaled_rgb = {srcr[x] * scale_r, \
243  srcg[x] * scale_g, \
244  srcb[x] * scale_b}; \
245  struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \
246  dstr[x] = av_clip_uintp2(vec.r * (float)((1<<depth) - 1), depth); \
247  dstg[x] = av_clip_uintp2(vec.g * (float)((1<<depth) - 1), depth); \
248  dstb[x] = av_clip_uintp2(vec.b * (float)((1<<depth) - 1), depth); \
249  if (!direct && in->linesize[3]) \
250  dsta[x] = srca[x]; \
251  } \
252  grow += out->linesize[0]; \
253  brow += out->linesize[1]; \
254  rrow += out->linesize[2]; \
255  arow += out->linesize[3]; \
256  srcgrow += in->linesize[0]; \
257  srcbrow += in->linesize[1]; \
258  srcrrow += in->linesize[2]; \
259  srcarow += in->linesize[3]; \
260  } \
261  return 0; \
262 }
263 
264 DEFINE_INTERP_FUNC_PLANAR(nearest, 8, 8)
265 DEFINE_INTERP_FUNC_PLANAR(trilinear, 8, 8)
266 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 8, 8)
267 
268 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 9)
269 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 9)
270 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 9)
271 
272 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 10)
273 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 10)
274 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 10)
275 
276 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 12)
277 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 12)
278 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 12)
279 
280 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 14)
281 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 14)
282 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 14)
283 
284 DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 16)
285 DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 16)
286 DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 16)
287 
288 #define DEFINE_INTERP_FUNC(name, nbits) \
289 static int interp_##nbits##_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
290 { \
291  int x, y; \
292  const LUT3DContext *lut3d = ctx->priv; \
293  const ThreadData *td = arg; \
294  const AVFrame *in = td->in; \
295  const AVFrame *out = td->out; \
296  const int direct = out == in; \
297  const int step = lut3d->step; \
298  const uint8_t r = lut3d->rgba_map[R]; \
299  const uint8_t g = lut3d->rgba_map[G]; \
300  const uint8_t b = lut3d->rgba_map[B]; \
301  const uint8_t a = lut3d->rgba_map[A]; \
302  const int slice_start = (in->height * jobnr ) / nb_jobs; \
303  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
304  uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \
305  const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \
306  const float scale_r = (lut3d->scale.r / ((1<<nbits) - 1)) * (lut3d->lutsize - 1); \
307  const float scale_g = (lut3d->scale.g / ((1<<nbits) - 1)) * (lut3d->lutsize - 1); \
308  const float scale_b = (lut3d->scale.b / ((1<<nbits) - 1)) * (lut3d->lutsize - 1); \
309  \
310  for (y = slice_start; y < slice_end; y++) { \
311  uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \
312  const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \
313  for (x = 0; x < in->width * step; x += step) { \
314  const struct rgbvec scaled_rgb = {src[x + r] * scale_r, \
315  src[x + g] * scale_g, \
316  src[x + b] * scale_b}; \
317  struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \
318  dst[x + r] = av_clip_uint##nbits(vec.r * (float)((1<<nbits) - 1)); \
319  dst[x + g] = av_clip_uint##nbits(vec.g * (float)((1<<nbits) - 1)); \
320  dst[x + b] = av_clip_uint##nbits(vec.b * (float)((1<<nbits) - 1)); \
321  if (!direct && step == 4) \
322  dst[x + a] = src[x + a]; \
323  } \
324  dstrow += out->linesize[0]; \
325  srcrow += in ->linesize[0]; \
326  } \
327  return 0; \
328 }
329 
330 DEFINE_INTERP_FUNC(nearest, 8)
331 DEFINE_INTERP_FUNC(trilinear, 8)
332 DEFINE_INTERP_FUNC(tetrahedral, 8)
333 
334 DEFINE_INTERP_FUNC(nearest, 16)
335 DEFINE_INTERP_FUNC(trilinear, 16)
336 DEFINE_INTERP_FUNC(tetrahedral, 16)
337 
338 #define MAX_LINE_SIZE 512
339 
340 static int skip_line(const char *p)
341 {
342  while (*p && av_isspace(*p))
343  p++;
344  return !*p || *p == '#';
345 }
346 
347 #define NEXT_LINE(loop_cond) do { \
348  if (!fgets(line, sizeof(line), f)) { \
349  av_log(ctx, AV_LOG_ERROR, "Unexpected EOF\n"); \
350  return AVERROR_INVALIDDATA; \
351  } \
352 } while (loop_cond)
353 
354 static int allocate_3dlut(AVFilterContext *ctx, int lutsize)
355 {
356  LUT3DContext *lut3d = ctx->priv;
357 
358  if (lutsize < 2 || lutsize > MAX_LEVEL) {
359  av_log(ctx, AV_LOG_ERROR, "Too large or invalid 3D LUT size\n");
360  return AVERROR(EINVAL);
361  }
362 
363  av_freep(&lut3d->lut);
364  lut3d->lut = av_malloc_array(lutsize * lutsize * lutsize, sizeof(*lut3d->lut));
365  if (!lut3d->lut)
366  return AVERROR(ENOMEM);
367  lut3d->lutsize = lutsize;
368  lut3d->lutsize2 = lutsize * lutsize;
369  return 0;
370 }
371 
372 /* Basically r g and b float values on each line, with a facultative 3DLUTSIZE
373  * directive; seems to be generated by Davinci */
374 static int parse_dat(AVFilterContext *ctx, FILE *f)
375 {
376  LUT3DContext *lut3d = ctx->priv;
377  char line[MAX_LINE_SIZE];
378  int ret, i, j, k, size, size2;
379 
380  lut3d->lutsize = size = 33;
381  size2 = size * size;
382 
383  NEXT_LINE(skip_line(line));
384  if (!strncmp(line, "3DLUTSIZE ", 10)) {
385  size = strtol(line + 10, NULL, 0);
386 
387  NEXT_LINE(skip_line(line));
388  }
389 
390  ret = allocate_3dlut(ctx, size);
391  if (ret < 0)
392  return ret;
393 
394  for (k = 0; k < size; k++) {
395  for (j = 0; j < size; j++) {
396  for (i = 0; i < size; i++) {
397  struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i];
398  if (k != 0 || j != 0 || i != 0)
399  NEXT_LINE(skip_line(line));
400  if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3)
401  return AVERROR_INVALIDDATA;
402  }
403  }
404  }
405  return 0;
406 }
407 
408 /* Iridas format */
409 static int parse_cube(AVFilterContext *ctx, FILE *f)
410 {
411  LUT3DContext *lut3d = ctx->priv;
412  char line[MAX_LINE_SIZE];
413  float min[3] = {0.0, 0.0, 0.0};
414  float max[3] = {1.0, 1.0, 1.0};
415 
416  while (fgets(line, sizeof(line), f)) {
417  if (!strncmp(line, "LUT_3D_SIZE", 11)) {
418  int ret, i, j, k;
419  const int size = strtol(line + 12, NULL, 0);
420  const int size2 = size * size;
421 
422  ret = allocate_3dlut(ctx, size);
423  if (ret < 0)
424  return ret;
425 
426  for (k = 0; k < size; k++) {
427  for (j = 0; j < size; j++) {
428  for (i = 0; i < size; i++) {
429  struct rgbvec *vec = &lut3d->lut[i * size2 + j * size + k];
430 
431  do {
432 try_again:
433  NEXT_LINE(0);
434  if (!strncmp(line, "DOMAIN_", 7)) {
435  float *vals = NULL;
436  if (!strncmp(line + 7, "MIN ", 4)) vals = min;
437  else if (!strncmp(line + 7, "MAX ", 4)) vals = max;
438  if (!vals)
439  return AVERROR_INVALIDDATA;
440  av_sscanf(line + 11, "%f %f %f", vals, vals + 1, vals + 2);
441  av_log(ctx, AV_LOG_DEBUG, "min: %f %f %f | max: %f %f %f\n",
442  min[0], min[1], min[2], max[0], max[1], max[2]);
443  goto try_again;
444  } else if (!strncmp(line, "TITLE", 5)) {
445  goto try_again;
446  }
447  } while (skip_line(line));
448  if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3)
449  return AVERROR_INVALIDDATA;
450  }
451  }
452  }
453  break;
454  }
455  }
456 
457  lut3d->scale.r = av_clipf(1. / (max[0] - min[0]), 0.f, 1.f);
458  lut3d->scale.g = av_clipf(1. / (max[1] - min[1]), 0.f, 1.f);
459  lut3d->scale.b = av_clipf(1. / (max[2] - min[2]), 0.f, 1.f);
460 
461  return 0;
462 }
463 
464 /* Assume 17x17x17 LUT with a 16-bit depth
465  * FIXME: it seems there are various 3dl formats */
466 static int parse_3dl(AVFilterContext *ctx, FILE *f)
467 {
468  char line[MAX_LINE_SIZE];
469  LUT3DContext *lut3d = ctx->priv;
470  int ret, i, j, k;
471  const int size = 17;
472  const int size2 = 17 * 17;
473  const float scale = 16*16*16;
474 
475  lut3d->lutsize = size;
476 
477  ret = allocate_3dlut(ctx, size);
478  if (ret < 0)
479  return ret;
480 
481  NEXT_LINE(skip_line(line));
482  for (k = 0; k < size; k++) {
483  for (j = 0; j < size; j++) {
484  for (i = 0; i < size; i++) {
485  int r, g, b;
486  struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i];
487 
488  NEXT_LINE(skip_line(line));
489  if (av_sscanf(line, "%d %d %d", &r, &g, &b) != 3)
490  return AVERROR_INVALIDDATA;
491  vec->r = r / scale;
492  vec->g = g / scale;
493  vec->b = b / scale;
494  }
495  }
496  }
497  return 0;
498 }
499 
500 /* Pandora format */
501 static int parse_m3d(AVFilterContext *ctx, FILE *f)
502 {
503  LUT3DContext *lut3d = ctx->priv;
504  float scale;
505  int ret, i, j, k, size, size2, in = -1, out = -1;
506  char line[MAX_LINE_SIZE];
507  uint8_t rgb_map[3] = {0, 1, 2};
508 
509  while (fgets(line, sizeof(line), f)) {
510  if (!strncmp(line, "in", 2)) in = strtol(line + 2, NULL, 0);
511  else if (!strncmp(line, "out", 3)) out = strtol(line + 3, NULL, 0);
512  else if (!strncmp(line, "values", 6)) {
513  const char *p = line + 6;
514 #define SET_COLOR(id) do { \
515  while (av_isspace(*p)) \
516  p++; \
517  switch (*p) { \
518  case 'r': rgb_map[id] = 0; break; \
519  case 'g': rgb_map[id] = 1; break; \
520  case 'b': rgb_map[id] = 2; break; \
521  } \
522  while (*p && !av_isspace(*p)) \
523  p++; \
524 } while (0)
525  SET_COLOR(0);
526  SET_COLOR(1);
527  SET_COLOR(2);
528  break;
529  }
530  }
531 
532  if (in == -1 || out == -1) {
533  av_log(ctx, AV_LOG_ERROR, "in and out must be defined\n");
534  return AVERROR_INVALIDDATA;
535  }
536  if (in < 2 || out < 2 ||
539  av_log(ctx, AV_LOG_ERROR, "invalid in (%d) or out (%d)\n", in, out);
540  return AVERROR_INVALIDDATA;
541  }
542  for (size = 1; size*size*size < in; size++);
543  lut3d->lutsize = size;
544  size2 = size * size;
545 
546  ret = allocate_3dlut(ctx, size);
547  if (ret < 0)
548  return ret;
549 
550  scale = 1. / (out - 1);
551 
552  for (k = 0; k < size; k++) {
553  for (j = 0; j < size; j++) {
554  for (i = 0; i < size; i++) {
555  struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i];
556  float val[3];
557 
558  NEXT_LINE(0);
559  if (av_sscanf(line, "%f %f %f", val, val + 1, val + 2) != 3)
560  return AVERROR_INVALIDDATA;
561  vec->r = val[rgb_map[0]] * scale;
562  vec->g = val[rgb_map[1]] * scale;
563  vec->b = val[rgb_map[2]] * scale;
564  }
565  }
566  }
567  return 0;
568 }
569 
571 {
572  LUT3DContext *lut3d = ctx->priv;
573  char line[MAX_LINE_SIZE];
574  float in_min[3] = {0.0, 0.0, 0.0};
575  float in_max[3] = {1.0, 1.0, 1.0};
576  float out_min[3] = {0.0, 0.0, 0.0};
577  float out_max[3] = {1.0, 1.0, 1.0};
578  int ret, inside_metadata = 0, size, size2;
579 
580  NEXT_LINE(skip_line(line));
581  if (strncmp(line, "CSPLUTV100", 10)) {
582  av_log(ctx, AV_LOG_ERROR, "Not cineSpace LUT format\n");
583  return AVERROR(EINVAL);
584  }
585 
586  NEXT_LINE(skip_line(line));
587  if (strncmp(line, "3D", 2)) {
588  av_log(ctx, AV_LOG_ERROR, "Not 3D LUT format\n");
589  return AVERROR(EINVAL);
590  }
591 
592  while (1) {
593  NEXT_LINE(skip_line(line));
594 
595  if (!strncmp(line, "BEGIN METADATA", 14)) {
596  inside_metadata = 1;
597  continue;
598  }
599  if (!strncmp(line, "END METADATA", 12)) {
600  inside_metadata = 0;
601  continue;
602  }
603  if (inside_metadata == 0) {
604  int size_r, size_g, size_b;
605 
606  for (int i = 0; i < 3; i++) {
607  int npoints = strtol(line, NULL, 0);
608 
609  if (npoints != 2) {
610  av_log(ctx, AV_LOG_ERROR, "Unsupported number of pre-lut points.\n");
611  return AVERROR_PATCHWELCOME;
612  }
613 
614  NEXT_LINE(skip_line(line));
615  if (av_sscanf(line, "%f %f", &in_min[i], &in_max[i]) != 2)
616  return AVERROR_INVALIDDATA;
617  NEXT_LINE(skip_line(line));
618  if (av_sscanf(line, "%f %f", &out_min[i], &out_max[i]) != 2)
619  return AVERROR_INVALIDDATA;
620  NEXT_LINE(skip_line(line));
621  }
622 
623  if (av_sscanf(line, "%d %d %d", &size_r, &size_g, &size_b) != 3)
624  return AVERROR(EINVAL);
625  if (size_r != size_g || size_r != size_b) {
626  av_log(ctx, AV_LOG_ERROR, "Unsupported size combination: %dx%dx%d.\n", size_r, size_g, size_b);
627  return AVERROR_PATCHWELCOME;
628  }
629 
630  size = size_r;
631  size2 = size * size;
632 
633  ret = allocate_3dlut(ctx, size);
634  if (ret < 0)
635  return ret;
636 
637  for (int k = 0; k < size; k++) {
638  for (int j = 0; j < size; j++) {
639  for (int i = 0; i < size; i++) {
640  struct rgbvec *vec = &lut3d->lut[i * size2 + j * size + k];
641  if (k != 0 || j != 0 || i != 0)
642  NEXT_LINE(skip_line(line));
643  if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3)
644  return AVERROR_INVALIDDATA;
645  vec->r *= out_max[0] - out_min[0];
646  vec->g *= out_max[1] - out_min[1];
647  vec->b *= out_max[2] - out_min[2];
648  }
649  }
650  }
651 
652  break;
653  }
654  }
655 
656  lut3d->scale.r = av_clipf(1. / (in_max[0] - in_min[0]), 0.f, 1.f);
657  lut3d->scale.g = av_clipf(1. / (in_max[1] - in_min[1]), 0.f, 1.f);
658  lut3d->scale.b = av_clipf(1. / (in_max[2] - in_min[2]), 0.f, 1.f);
659 
660  return 0;
661 }
662 
664 {
665  LUT3DContext *lut3d = ctx->priv;
666  int ret, i, j, k;
667  const int size2 = size * size;
668  const float c = 1. / (size - 1);
669 
670  ret = allocate_3dlut(ctx, size);
671  if (ret < 0)
672  return ret;
673 
674  for (k = 0; k < size; k++) {
675  for (j = 0; j < size; j++) {
676  for (i = 0; i < size; i++) {
677  struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i];
678  vec->r = k * c;
679  vec->g = j * c;
680  vec->b = i * c;
681  }
682  }
683  }
684 
685  return 0;
686 }
687 
689 {
690  static const enum AVPixelFormat pix_fmts[] = {
705  };
706  AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
707  if (!fmts_list)
708  return AVERROR(ENOMEM);
709  return ff_set_common_formats(ctx, fmts_list);
710 }
711 
713 {
714  int depth, is16bit, planar;
715  LUT3DContext *lut3d = inlink->dst->priv;
717 
718  depth = desc->comp[0].depth;
719  is16bit = desc->comp[0].depth > 8;
720  planar = desc->flags & AV_PIX_FMT_FLAG_PLANAR;
721  ff_fill_rgba_map(lut3d->rgba_map, inlink->format);
722  lut3d->step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit);
723 
724 #define SET_FUNC(name) do { \
725  if (planar) { \
726  switch (depth) { \
727  case 8: lut3d->interp = interp_8_##name##_p8; break; \
728  case 9: lut3d->interp = interp_16_##name##_p9; break; \
729  case 10: lut3d->interp = interp_16_##name##_p10; break; \
730  case 12: lut3d->interp = interp_16_##name##_p12; break; \
731  case 14: lut3d->interp = interp_16_##name##_p14; break; \
732  case 16: lut3d->interp = interp_16_##name##_p16; break; \
733  } \
734  } else if (is16bit) { lut3d->interp = interp_16_##name; \
735  } else { lut3d->interp = interp_8_##name; } \
736 } while (0)
737 
738  switch (lut3d->interpolation) {
739  case INTERPOLATE_NEAREST: SET_FUNC(nearest); break;
740  case INTERPOLATE_TRILINEAR: SET_FUNC(trilinear); break;
741  case INTERPOLATE_TETRAHEDRAL: SET_FUNC(tetrahedral); break;
742  default:
743  av_assert0(0);
744  }
745 
746  return 0;
747 }
748 
750 {
751  AVFilterContext *ctx = inlink->dst;
752  LUT3DContext *lut3d = ctx->priv;
753  AVFilterLink *outlink = inlink->dst->outputs[0];
754  AVFrame *out;
755  ThreadData td;
756 
757  if (av_frame_is_writable(in)) {
758  out = in;
759  } else {
760  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
761  if (!out) {
762  av_frame_free(&in);
763  return NULL;
764  }
765  av_frame_copy_props(out, in);
766  }
767 
768  td.in = in;
769  td.out = out;
770  ctx->internal->execute(ctx, lut3d->interp, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
771 
772  if (out != in)
773  av_frame_free(&in);
774 
775  return out;
776 }
777 
779 {
780  AVFilterLink *outlink = inlink->dst->outputs[0];
781  AVFrame *out = apply_lut(inlink, in);
782  if (!out)
783  return AVERROR(ENOMEM);
784  return ff_filter_frame(outlink, out);
785 }
786 
787 #if CONFIG_LUT3D_FILTER
788 static const AVOption lut3d_options[] = {
789  { "file", "set 3D LUT file name", OFFSET(file), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
791 };
792 
793 AVFILTER_DEFINE_CLASS(lut3d);
794 
795 static av_cold int lut3d_init(AVFilterContext *ctx)
796 {
797  int ret;
798  FILE *f;
799  const char *ext;
800  LUT3DContext *lut3d = ctx->priv;
801 
802  lut3d->scale.r = lut3d->scale.g = lut3d->scale.b = 1.f;
803 
804  if (!lut3d->file) {
805  return set_identity_matrix(ctx, 32);
806  }
807 
808  f = fopen(lut3d->file, "r");
809  if (!f) {
810  ret = AVERROR(errno);
811  av_log(ctx, AV_LOG_ERROR, "%s: %s\n", lut3d->file, av_err2str(ret));
812  return ret;
813  }
814 
815  ext = strrchr(lut3d->file, '.');
816  if (!ext) {
817  av_log(ctx, AV_LOG_ERROR, "Unable to guess the format from the extension\n");
818  ret = AVERROR_INVALIDDATA;
819  goto end;
820  }
821  ext++;
822 
823  if (!av_strcasecmp(ext, "dat")) {
824  ret = parse_dat(ctx, f);
825  } else if (!av_strcasecmp(ext, "3dl")) {
826  ret = parse_3dl(ctx, f);
827  } else if (!av_strcasecmp(ext, "cube")) {
828  ret = parse_cube(ctx, f);
829  } else if (!av_strcasecmp(ext, "m3d")) {
830  ret = parse_m3d(ctx, f);
831  } else if (!av_strcasecmp(ext, "csp")) {
832  ret = parse_cinespace(ctx, f);
833  } else {
834  av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext);
835  ret = AVERROR(EINVAL);
836  }
837 
838  if (!ret && !lut3d->lutsize) {
839  av_log(ctx, AV_LOG_ERROR, "3D LUT is empty\n");
840  ret = AVERROR_INVALIDDATA;
841  }
842 
843 end:
844  fclose(f);
845  return ret;
846 }
847 
848 static av_cold void lut3d_uninit(AVFilterContext *ctx)
849 {
850  LUT3DContext *lut3d = ctx->priv;
851 
852  av_freep(&lut3d->lut);
853 }
854 
855 static const AVFilterPad lut3d_inputs[] = {
856  {
857  .name = "default",
858  .type = AVMEDIA_TYPE_VIDEO,
859  .filter_frame = filter_frame,
860  .config_props = config_input,
861  },
862  { NULL }
863 };
864 
865 static const AVFilterPad lut3d_outputs[] = {
866  {
867  .name = "default",
868  .type = AVMEDIA_TYPE_VIDEO,
869  },
870  { NULL }
871 };
872 
874  .name = "lut3d",
875  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a 3D LUT."),
876  .priv_size = sizeof(LUT3DContext),
877  .init = lut3d_init,
878  .uninit = lut3d_uninit,
880  .inputs = lut3d_inputs,
881  .outputs = lut3d_outputs,
882  .priv_class = &lut3d_class,
884 };
885 #endif
886 
887 #if CONFIG_HALDCLUT_FILTER
888 
889 static void update_clut_packed(LUT3DContext *lut3d, const AVFrame *frame)
890 {
891  const uint8_t *data = frame->data[0];
892  const int linesize = frame->linesize[0];
893  const int w = lut3d->clut_width;
894  const int step = lut3d->clut_step;
895  const uint8_t *rgba_map = lut3d->clut_rgba_map;
896  const int level = lut3d->lutsize;
897  const int level2 = lut3d->lutsize2;
898 
899 #define LOAD_CLUT(nbits) do { \
900  int i, j, k, x = 0, y = 0; \
901  \
902  for (k = 0; k < level; k++) { \
903  for (j = 0; j < level; j++) { \
904  for (i = 0; i < level; i++) { \
905  const uint##nbits##_t *src = (const uint##nbits##_t *) \
906  (data + y*linesize + x*step); \
907  struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k]; \
908  vec->r = src[rgba_map[0]] / (float)((1<<(nbits)) - 1); \
909  vec->g = src[rgba_map[1]] / (float)((1<<(nbits)) - 1); \
910  vec->b = src[rgba_map[2]] / (float)((1<<(nbits)) - 1); \
911  if (++x == w) { \
912  x = 0; \
913  y++; \
914  } \
915  } \
916  } \
917  } \
918 } while (0)
919 
920  switch (lut3d->clut_bits) {
921  case 8: LOAD_CLUT(8); break;
922  case 16: LOAD_CLUT(16); break;
923  }
924 }
925 
926 static void update_clut_planar(LUT3DContext *lut3d, const AVFrame *frame)
927 {
928  const uint8_t *datag = frame->data[0];
929  const uint8_t *datab = frame->data[1];
930  const uint8_t *datar = frame->data[2];
931  const int glinesize = frame->linesize[0];
932  const int blinesize = frame->linesize[1];
933  const int rlinesize = frame->linesize[2];
934  const int w = lut3d->clut_width;
935  const int level = lut3d->lutsize;
936  const int level2 = lut3d->lutsize2;
937 
938 #define LOAD_CLUT_PLANAR(nbits, depth) do { \
939  int i, j, k, x = 0, y = 0; \
940  \
941  for (k = 0; k < level; k++) { \
942  for (j = 0; j < level; j++) { \
943  for (i = 0; i < level; i++) { \
944  const uint##nbits##_t *gsrc = (const uint##nbits##_t *) \
945  (datag + y*glinesize); \
946  const uint##nbits##_t *bsrc = (const uint##nbits##_t *) \
947  (datab + y*blinesize); \
948  const uint##nbits##_t *rsrc = (const uint##nbits##_t *) \
949  (datar + y*rlinesize); \
950  struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k]; \
951  vec->r = gsrc[x] / (float)((1<<(depth)) - 1); \
952  vec->g = bsrc[x] / (float)((1<<(depth)) - 1); \
953  vec->b = rsrc[x] / (float)((1<<(depth)) - 1); \
954  if (++x == w) { \
955  x = 0; \
956  y++; \
957  } \
958  } \
959  } \
960  } \
961 } while (0)
962 
963  switch (lut3d->clut_bits) {
964  case 8: LOAD_CLUT_PLANAR(8, 8); break;
965  case 9: LOAD_CLUT_PLANAR(16, 9); break;
966  case 10: LOAD_CLUT_PLANAR(16, 10); break;
967  case 12: LOAD_CLUT_PLANAR(16, 12); break;
968  case 14: LOAD_CLUT_PLANAR(16, 14); break;
969  case 16: LOAD_CLUT_PLANAR(16, 16); break;
970  }
971 }
972 
973 static int config_output(AVFilterLink *outlink)
974 {
975  AVFilterContext *ctx = outlink->src;
976  LUT3DContext *lut3d = ctx->priv;
977  int ret;
978 
979  ret = ff_framesync_init_dualinput(&lut3d->fs, ctx);
980  if (ret < 0)
981  return ret;
982  outlink->w = ctx->inputs[0]->w;
983  outlink->h = ctx->inputs[0]->h;
984  outlink->time_base = ctx->inputs[0]->time_base;
985  if ((ret = ff_framesync_configure(&lut3d->fs)) < 0)
986  return ret;
987  return 0;
988 }
989 
990 static int activate(AVFilterContext *ctx)
991 {
992  LUT3DContext *s = ctx->priv;
993  return ff_framesync_activate(&s->fs);
994 }
995 
996 static int config_clut(AVFilterLink *inlink)
997 {
998  int size, level, w, h;
999  AVFilterContext *ctx = inlink->dst;
1000  LUT3DContext *lut3d = ctx->priv;
1002 
1003  av_assert0(desc);
1004 
1005  lut3d->clut_bits = desc->comp[0].depth;
1006  lut3d->clut_planar = av_pix_fmt_count_planes(inlink->format) > 1;
1007 
1008  lut3d->clut_step = av_get_padded_bits_per_pixel(desc) >> 3;
1009  ff_fill_rgba_map(lut3d->clut_rgba_map, inlink->format);
1010 
1011  if (inlink->w > inlink->h)
1012  av_log(ctx, AV_LOG_INFO, "Padding on the right (%dpx) of the "
1013  "Hald CLUT will be ignored\n", inlink->w - inlink->h);
1014  else if (inlink->w < inlink->h)
1015  av_log(ctx, AV_LOG_INFO, "Padding at the bottom (%dpx) of the "
1016  "Hald CLUT will be ignored\n", inlink->h - inlink->w);
1017  lut3d->clut_width = w = h = FFMIN(inlink->w, inlink->h);
1018 
1019  for (level = 1; level*level*level < w; level++);
1020  size = level*level*level;
1021  if (size != w) {
1022  av_log(ctx, AV_LOG_WARNING, "The Hald CLUT width does not match the level\n");
1023  return AVERROR_INVALIDDATA;
1024  }
1025  av_assert0(w == h && w == size);
1026  level *= level;
1027  if (level > MAX_LEVEL) {
1028  const int max_clut_level = sqrt(MAX_LEVEL);
1029  const int max_clut_size = max_clut_level*max_clut_level*max_clut_level;
1030  av_log(ctx, AV_LOG_ERROR, "Too large Hald CLUT "
1031  "(maximum level is %d, or %dx%d CLUT)\n",
1032  max_clut_level, max_clut_size, max_clut_size);
1033  return AVERROR(EINVAL);
1034  }
1035 
1036  return allocate_3dlut(ctx, level);
1037 }
1038 
1039 static int update_apply_clut(FFFrameSync *fs)
1040 {
1041  AVFilterContext *ctx = fs->parent;
1042  LUT3DContext *lut3d = ctx->priv;
1043  AVFilterLink *inlink = ctx->inputs[0];
1044  AVFrame *master, *second, *out;
1045  int ret;
1046 
1047  ret = ff_framesync_dualinput_get(fs, &master, &second);
1048  if (ret < 0)
1049  return ret;
1050  if (!second)
1051  return ff_filter_frame(ctx->outputs[0], master);
1052  if (lut3d->clut_planar)
1053  update_clut_planar(ctx->priv, second);
1054  else
1055  update_clut_packed(ctx->priv, second);
1056  out = apply_lut(inlink, master);
1057  return ff_filter_frame(ctx->outputs[0], out);
1058 }
1059 
1060 static av_cold int haldclut_init(AVFilterContext *ctx)
1061 {
1062  LUT3DContext *lut3d = ctx->priv;
1063  lut3d->scale.r = lut3d->scale.g = lut3d->scale.b = 1.f;
1064  lut3d->fs.on_event = update_apply_clut;
1065  return 0;
1066 }
1067 
1068 static av_cold void haldclut_uninit(AVFilterContext *ctx)
1069 {
1070  LUT3DContext *lut3d = ctx->priv;
1071  ff_framesync_uninit(&lut3d->fs);
1072  av_freep(&lut3d->lut);
1073 }
1074 
1075 static const AVOption haldclut_options[] = {
1076  COMMON_OPTIONS
1077 };
1078 
1079 FRAMESYNC_DEFINE_CLASS(haldclut, LUT3DContext, fs);
1080 
1081 static const AVFilterPad haldclut_inputs[] = {
1082  {
1083  .name = "main",
1084  .type = AVMEDIA_TYPE_VIDEO,
1085  .config_props = config_input,
1086  },{
1087  .name = "clut",
1088  .type = AVMEDIA_TYPE_VIDEO,
1089  .config_props = config_clut,
1090  },
1091  { NULL }
1092 };
1093 
1094 static const AVFilterPad haldclut_outputs[] = {
1095  {
1096  .name = "default",
1097  .type = AVMEDIA_TYPE_VIDEO,
1098  .config_props = config_output,
1099  },
1100  { NULL }
1101 };
1102 
1104  .name = "haldclut",
1105  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a Hald CLUT."),
1106  .priv_size = sizeof(LUT3DContext),
1107  .preinit = haldclut_framesync_preinit,
1108  .init = haldclut_init,
1109  .uninit = haldclut_uninit,
1111  .activate = activate,
1112  .inputs = haldclut_inputs,
1113  .outputs = haldclut_outputs,
1114  .priv_class = &haldclut_class,
1116 };
1117 #endif
1118 
1119 #if CONFIG_LUT1D_FILTER
1120 
1121 enum interp_1d_mode {
1122  INTERPOLATE_1D_NEAREST,
1123  INTERPOLATE_1D_LINEAR,
1124  INTERPOLATE_1D_CUBIC,
1125  INTERPOLATE_1D_COSINE,
1126  INTERPOLATE_1D_SPLINE,
1127  NB_INTERP_1D_MODE
1128 };
1129 
1130 #define MAX_1D_LEVEL 65536
1131 
1132 typedef struct LUT1DContext {
1133  const AVClass *class;
1134  char *file;
1135  int interpolation; ///<interp_1d_mode
1136  struct rgbvec scale;
1137  uint8_t rgba_map[4];
1138  int step;
1139  float lut[3][MAX_1D_LEVEL];
1140  int lutsize;
1141  avfilter_action_func *interp;
1142 } LUT1DContext;
1143 
1144 #undef OFFSET
1145 #define OFFSET(x) offsetof(LUT1DContext, x)
1146 
1147 static void set_identity_matrix_1d(LUT1DContext *lut1d, int size)
1148 {
1149  const float c = 1. / (size - 1);
1150  int i;
1151 
1152  lut1d->lutsize = size;
1153  for (i = 0; i < size; i++) {
1154  lut1d->lut[0][i] = i * c;
1155  lut1d->lut[1][i] = i * c;
1156  lut1d->lut[2][i] = i * c;
1157  }
1158 }
1159 
1160 static int parse_cinespace_1d(AVFilterContext *ctx, FILE *f)
1161 {
1162  LUT1DContext *lut1d = ctx->priv;
1163  char line[MAX_LINE_SIZE];
1164  float in_min[3] = {0.0, 0.0, 0.0};
1165  float in_max[3] = {1.0, 1.0, 1.0};
1166  float out_min[3] = {0.0, 0.0, 0.0};
1167  float out_max[3] = {1.0, 1.0, 1.0};
1168  int inside_metadata = 0, size;
1169 
1170  NEXT_LINE(skip_line(line));
1171  if (strncmp(line, "CSPLUTV100", 10)) {
1172  av_log(ctx, AV_LOG_ERROR, "Not cineSpace LUT format\n");
1173  return AVERROR(EINVAL);
1174  }
1175 
1176  NEXT_LINE(skip_line(line));
1177  if (strncmp(line, "1D", 2)) {
1178  av_log(ctx, AV_LOG_ERROR, "Not 1D LUT format\n");
1179  return AVERROR(EINVAL);
1180  }
1181 
1182  while (1) {
1183  NEXT_LINE(skip_line(line));
1184 
1185  if (!strncmp(line, "BEGIN METADATA", 14)) {
1186  inside_metadata = 1;
1187  continue;
1188  }
1189  if (!strncmp(line, "END METADATA", 12)) {
1190  inside_metadata = 0;
1191  continue;
1192  }
1193  if (inside_metadata == 0) {
1194  for (int i = 0; i < 3; i++) {
1195  int npoints = strtol(line, NULL, 0);
1196 
1197  if (npoints != 2) {
1198  av_log(ctx, AV_LOG_ERROR, "Unsupported number of pre-lut points.\n");
1199  return AVERROR_PATCHWELCOME;
1200  }
1201 
1202  NEXT_LINE(skip_line(line));
1203  if (av_sscanf(line, "%f %f", &in_min[i], &in_max[i]) != 2)
1204  return AVERROR_INVALIDDATA;
1205  NEXT_LINE(skip_line(line));
1206  if (av_sscanf(line, "%f %f", &out_min[i], &out_max[i]) != 2)
1207  return AVERROR_INVALIDDATA;
1208  NEXT_LINE(skip_line(line));
1209  }
1210 
1211  size = strtol(line, NULL, 0);
1212 
1213  if (size < 2 || size > MAX_1D_LEVEL) {
1214  av_log(ctx, AV_LOG_ERROR, "Too large or invalid 1D LUT size\n");
1215  return AVERROR(EINVAL);
1216  }
1217 
1218  lut1d->lutsize = size;
1219 
1220  for (int i = 0; i < size; i++) {
1221  NEXT_LINE(skip_line(line));
1222  if (av_sscanf(line, "%f %f %f", &lut1d->lut[0][i], &lut1d->lut[1][i], &lut1d->lut[2][i]) != 3)
1223  return AVERROR_INVALIDDATA;
1224  lut1d->lut[0][i] *= out_max[0] - out_min[0];
1225  lut1d->lut[1][i] *= out_max[1] - out_min[1];
1226  lut1d->lut[2][i] *= out_max[2] - out_min[2];
1227  }
1228 
1229  break;
1230  }
1231  }
1232 
1233  lut1d->scale.r = av_clipf(1. / (in_max[0] - in_min[0]), 0.f, 1.f);
1234  lut1d->scale.g = av_clipf(1. / (in_max[1] - in_min[1]), 0.f, 1.f);
1235  lut1d->scale.b = av_clipf(1. / (in_max[2] - in_min[2]), 0.f, 1.f);
1236 
1237  return 0;
1238 }
1239 
1240 static int parse_cube_1d(AVFilterContext *ctx, FILE *f)
1241 {
1242  LUT1DContext *lut1d = ctx->priv;
1243  char line[MAX_LINE_SIZE];
1244  float min[3] = {0.0, 0.0, 0.0};
1245  float max[3] = {1.0, 1.0, 1.0};
1246 
1247  while (fgets(line, sizeof(line), f)) {
1248  if (!strncmp(line, "LUT_1D_SIZE", 11)) {
1249  const int size = strtol(line + 12, NULL, 0);
1250  int i;
1251 
1252  if (size < 2 || size > MAX_1D_LEVEL) {
1253  av_log(ctx, AV_LOG_ERROR, "Too large or invalid 1D LUT size\n");
1254  return AVERROR(EINVAL);
1255  }
1256  lut1d->lutsize = size;
1257  for (i = 0; i < size; i++) {
1258  do {
1259 try_again:
1260  NEXT_LINE(0);
1261  if (!strncmp(line, "DOMAIN_", 7)) {
1262  float *vals = NULL;
1263  if (!strncmp(line + 7, "MIN ", 4)) vals = min;
1264  else if (!strncmp(line + 7, "MAX ", 4)) vals = max;
1265  if (!vals)
1266  return AVERROR_INVALIDDATA;
1267  av_sscanf(line + 11, "%f %f %f", vals, vals + 1, vals + 2);
1268  av_log(ctx, AV_LOG_DEBUG, "min: %f %f %f | max: %f %f %f\n",
1269  min[0], min[1], min[2], max[0], max[1], max[2]);
1270  goto try_again;
1271  } else if (!strncmp(line, "LUT_1D_INPUT_RANGE ", 19)) {
1272  av_sscanf(line + 19, "%f %f", min, max);
1273  min[1] = min[2] = min[0];
1274  max[1] = max[2] = max[0];
1275  goto try_again;
1276  } else if (!strncmp(line, "TITLE", 5)) {
1277  goto try_again;
1278  }
1279  } while (skip_line(line));
1280  if (av_sscanf(line, "%f %f %f", &lut1d->lut[0][i], &lut1d->lut[1][i], &lut1d->lut[2][i]) != 3)
1281  return AVERROR_INVALIDDATA;
1282  }
1283  break;
1284  }
1285  }
1286 
1287  lut1d->scale.r = av_clipf(1. / (max[0] - min[0]), 0.f, 1.f);
1288  lut1d->scale.g = av_clipf(1. / (max[1] - min[1]), 0.f, 1.f);
1289  lut1d->scale.b = av_clipf(1. / (max[2] - min[2]), 0.f, 1.f);
1290 
1291  return 0;
1292 }
1293 
1294 static const AVOption lut1d_options[] = {
1295  { "file", "set 1D LUT file name", OFFSET(file), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
1296  { "interp", "select interpolation mode", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=INTERPOLATE_1D_LINEAR}, 0, NB_INTERP_1D_MODE-1, FLAGS, "interp_mode" },
1297  { "nearest", "use values from the nearest defined points", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_NEAREST}, INT_MIN, INT_MAX, FLAGS, "interp_mode" },
1298  { "linear", "use values from the linear interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_LINEAR}, INT_MIN, INT_MAX, FLAGS, "interp_mode" },
1299  { "cosine", "use values from the cosine interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_COSINE}, INT_MIN, INT_MAX, FLAGS, "interp_mode" },
1300  { "cubic", "use values from the cubic interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_CUBIC}, INT_MIN, INT_MAX, FLAGS, "interp_mode" },
1301  { "spline", "use values from the spline interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_SPLINE}, INT_MIN, INT_MAX, FLAGS, "interp_mode" },
1302  { NULL }
1303 };
1304 
1305 AVFILTER_DEFINE_CLASS(lut1d);
1306 
1307 static inline float interp_1d_nearest(const LUT1DContext *lut1d,
1308  int idx, const float s)
1309 {
1310  return lut1d->lut[idx][NEAR(s)];
1311 }
1312 
1313 #define NEXT1D(x) (FFMIN((int)(x) + 1, lut1d->lutsize - 1))
1314 
1315 static inline float interp_1d_linear(const LUT1DContext *lut1d,
1316  int idx, const float s)
1317 {
1318  const int prev = PREV(s);
1319  const int next = NEXT1D(s);
1320  const float d = s - prev;
1321  const float p = lut1d->lut[idx][prev];
1322  const float n = lut1d->lut[idx][next];
1323 
1324  return lerpf(p, n, d);
1325 }
1326 
1327 static inline float interp_1d_cosine(const LUT1DContext *lut1d,
1328  int idx, const float s)
1329 {
1330  const int prev = PREV(s);
1331  const int next = NEXT1D(s);
1332  const float d = s - prev;
1333  const float p = lut1d->lut[idx][prev];
1334  const float n = lut1d->lut[idx][next];
1335  const float m = (1.f - cosf(d * M_PI)) * .5f;
1336 
1337  return lerpf(p, n, m);
1338 }
1339 
1340 static inline float interp_1d_cubic(const LUT1DContext *lut1d,
1341  int idx, const float s)
1342 {
1343  const int prev = PREV(s);
1344  const int next = NEXT1D(s);
1345  const float mu = s - prev;
1346  float a0, a1, a2, a3, mu2;
1347 
1348  float y0 = lut1d->lut[idx][FFMAX(prev - 1, 0)];
1349  float y1 = lut1d->lut[idx][prev];
1350  float y2 = lut1d->lut[idx][next];
1351  float y3 = lut1d->lut[idx][FFMIN(next + 1, lut1d->lutsize - 1)];
1352 
1353 
1354  mu2 = mu * mu;
1355  a0 = y3 - y2 - y0 + y1;
1356  a1 = y0 - y1 - a0;
1357  a2 = y2 - y0;
1358  a3 = y1;
1359 
1360  return a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3;
1361 }
1362 
1363 static inline float interp_1d_spline(const LUT1DContext *lut1d,
1364  int idx, const float s)
1365 {
1366  const int prev = PREV(s);
1367  const int next = NEXT1D(s);
1368  const float x = s - prev;
1369  float c0, c1, c2, c3;
1370 
1371  float y0 = lut1d->lut[idx][FFMAX(prev - 1, 0)];
1372  float y1 = lut1d->lut[idx][prev];
1373  float y2 = lut1d->lut[idx][next];
1374  float y3 = lut1d->lut[idx][FFMIN(next + 1, lut1d->lutsize - 1)];
1375 
1376  c0 = y1;
1377  c1 = .5f * (y2 - y0);
1378  c2 = y0 - 2.5f * y1 + 2.f * y2 - .5f * y3;
1379  c3 = .5f * (y3 - y0) + 1.5f * (y1 - y2);
1380 
1381  return ((c3 * x + c2) * x + c1) * x + c0;
1382 }
1383 
1384 #define DEFINE_INTERP_FUNC_PLANAR_1D(name, nbits, depth) \
1385 static int interp_1d_##nbits##_##name##_p##depth(AVFilterContext *ctx, \
1386  void *arg, int jobnr, \
1387  int nb_jobs) \
1388 { \
1389  int x, y; \
1390  const LUT1DContext *lut1d = ctx->priv; \
1391  const ThreadData *td = arg; \
1392  const AVFrame *in = td->in; \
1393  const AVFrame *out = td->out; \
1394  const int direct = out == in; \
1395  const int slice_start = (in->height * jobnr ) / nb_jobs; \
1396  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
1397  uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
1398  uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
1399  uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
1400  uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
1401  const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
1402  const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
1403  const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
1404  const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
1405  const float factor = (1 << depth) - 1; \
1406  const float scale_r = (lut1d->scale.r / factor) * (lut1d->lutsize - 1); \
1407  const float scale_g = (lut1d->scale.g / factor) * (lut1d->lutsize - 1); \
1408  const float scale_b = (lut1d->scale.b / factor) * (lut1d->lutsize - 1); \
1409  \
1410  for (y = slice_start; y < slice_end; y++) { \
1411  uint##nbits##_t *dstg = (uint##nbits##_t *)grow; \
1412  uint##nbits##_t *dstb = (uint##nbits##_t *)brow; \
1413  uint##nbits##_t *dstr = (uint##nbits##_t *)rrow; \
1414  uint##nbits##_t *dsta = (uint##nbits##_t *)arow; \
1415  const uint##nbits##_t *srcg = (const uint##nbits##_t *)srcgrow; \
1416  const uint##nbits##_t *srcb = (const uint##nbits##_t *)srcbrow; \
1417  const uint##nbits##_t *srcr = (const uint##nbits##_t *)srcrrow; \
1418  const uint##nbits##_t *srca = (const uint##nbits##_t *)srcarow; \
1419  for (x = 0; x < in->width; x++) { \
1420  float r = srcr[x] * scale_r; \
1421  float g = srcg[x] * scale_g; \
1422  float b = srcb[x] * scale_b; \
1423  r = interp_1d_##name(lut1d, 0, r); \
1424  g = interp_1d_##name(lut1d, 1, g); \
1425  b = interp_1d_##name(lut1d, 2, b); \
1426  dstr[x] = av_clip_uintp2(r * factor, depth); \
1427  dstg[x] = av_clip_uintp2(g * factor, depth); \
1428  dstb[x] = av_clip_uintp2(b * factor, depth); \
1429  if (!direct && in->linesize[3]) \
1430  dsta[x] = srca[x]; \
1431  } \
1432  grow += out->linesize[0]; \
1433  brow += out->linesize[1]; \
1434  rrow += out->linesize[2]; \
1435  arow += out->linesize[3]; \
1436  srcgrow += in->linesize[0]; \
1437  srcbrow += in->linesize[1]; \
1438  srcrrow += in->linesize[2]; \
1439  srcarow += in->linesize[3]; \
1440  } \
1441  return 0; \
1442 }
1443 
1444 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 8, 8)
1445 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 8, 8)
1446 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 8, 8)
1447 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 8, 8)
1448 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 8, 8)
1449 
1450 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 9)
1451 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 9)
1452 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 9)
1453 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 9)
1454 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 9)
1455 
1456 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 10)
1457 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 10)
1458 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 10)
1459 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 10)
1460 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 10)
1461 
1462 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 12)
1463 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 12)
1464 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 12)
1465 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 12)
1466 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 12)
1467 
1468 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 14)
1469 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 14)
1470 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 14)
1471 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 14)
1472 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 14)
1473 
1474 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 16)
1475 DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 16)
1476 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 16)
1477 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 16)
1478 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 16)
1479 
1480 #define DEFINE_INTERP_FUNC_1D(name, nbits) \
1481 static int interp_1d_##nbits##_##name(AVFilterContext *ctx, void *arg, \
1482  int jobnr, int nb_jobs) \
1483 { \
1484  int x, y; \
1485  const LUT1DContext *lut1d = ctx->priv; \
1486  const ThreadData *td = arg; \
1487  const AVFrame *in = td->in; \
1488  const AVFrame *out = td->out; \
1489  const int direct = out == in; \
1490  const int step = lut1d->step; \
1491  const uint8_t r = lut1d->rgba_map[R]; \
1492  const uint8_t g = lut1d->rgba_map[G]; \
1493  const uint8_t b = lut1d->rgba_map[B]; \
1494  const uint8_t a = lut1d->rgba_map[A]; \
1495  const int slice_start = (in->height * jobnr ) / nb_jobs; \
1496  const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
1497  uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \
1498  const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \
1499  const float factor = (1 << nbits) - 1; \
1500  const float scale_r = (lut1d->scale.r / factor) * (lut1d->lutsize - 1); \
1501  const float scale_g = (lut1d->scale.g / factor) * (lut1d->lutsize - 1); \
1502  const float scale_b = (lut1d->scale.b / factor) * (lut1d->lutsize - 1); \
1503  \
1504  for (y = slice_start; y < slice_end; y++) { \
1505  uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \
1506  const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \
1507  for (x = 0; x < in->width * step; x += step) { \
1508  float rr = src[x + r] * scale_r; \
1509  float gg = src[x + g] * scale_g; \
1510  float bb = src[x + b] * scale_b; \
1511  rr = interp_1d_##name(lut1d, 0, rr); \
1512  gg = interp_1d_##name(lut1d, 1, gg); \
1513  bb = interp_1d_##name(lut1d, 2, bb); \
1514  dst[x + r] = av_clip_uint##nbits(rr * factor); \
1515  dst[x + g] = av_clip_uint##nbits(gg * factor); \
1516  dst[x + b] = av_clip_uint##nbits(bb * factor); \
1517  if (!direct && step == 4) \
1518  dst[x + a] = src[x + a]; \
1519  } \
1520  dstrow += out->linesize[0]; \
1521  srcrow += in ->linesize[0]; \
1522  } \
1523  return 0; \
1524 }
1525 
1526 DEFINE_INTERP_FUNC_1D(nearest, 8)
1527 DEFINE_INTERP_FUNC_1D(linear, 8)
1528 DEFINE_INTERP_FUNC_1D(cosine, 8)
1529 DEFINE_INTERP_FUNC_1D(cubic, 8)
1530 DEFINE_INTERP_FUNC_1D(spline, 8)
1531 
1532 DEFINE_INTERP_FUNC_1D(nearest, 16)
1533 DEFINE_INTERP_FUNC_1D(linear, 16)
1534 DEFINE_INTERP_FUNC_1D(cosine, 16)
1535 DEFINE_INTERP_FUNC_1D(cubic, 16)
1536 DEFINE_INTERP_FUNC_1D(spline, 16)
1537 
1538 static int config_input_1d(AVFilterLink *inlink)
1539 {
1540  int depth, is16bit, planar;
1541  LUT1DContext *lut1d = inlink->dst->priv;
1543 
1544  depth = desc->comp[0].depth;
1545  is16bit = desc->comp[0].depth > 8;
1546  planar = desc->flags & AV_PIX_FMT_FLAG_PLANAR;
1547  ff_fill_rgba_map(lut1d->rgba_map, inlink->format);
1548  lut1d->step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit);
1549 
1550 #define SET_FUNC_1D(name) do { \
1551  if (planar) { \
1552  switch (depth) { \
1553  case 8: lut1d->interp = interp_1d_8_##name##_p8; break; \
1554  case 9: lut1d->interp = interp_1d_16_##name##_p9; break; \
1555  case 10: lut1d->interp = interp_1d_16_##name##_p10; break; \
1556  case 12: lut1d->interp = interp_1d_16_##name##_p12; break; \
1557  case 14: lut1d->interp = interp_1d_16_##name##_p14; break; \
1558  case 16: lut1d->interp = interp_1d_16_##name##_p16; break; \
1559  } \
1560  } else if (is16bit) { lut1d->interp = interp_1d_16_##name; \
1561  } else { lut1d->interp = interp_1d_8_##name; } \
1562 } while (0)
1563 
1564  switch (lut1d->interpolation) {
1565  case INTERPOLATE_1D_NEAREST: SET_FUNC_1D(nearest); break;
1566  case INTERPOLATE_1D_LINEAR: SET_FUNC_1D(linear); break;
1567  case INTERPOLATE_1D_COSINE: SET_FUNC_1D(cosine); break;
1568  case INTERPOLATE_1D_CUBIC: SET_FUNC_1D(cubic); break;
1569  case INTERPOLATE_1D_SPLINE: SET_FUNC_1D(spline); break;
1570  default:
1571  av_assert0(0);
1572  }
1573 
1574  return 0;
1575 }
1576 
1577 static av_cold int lut1d_init(AVFilterContext *ctx)
1578 {
1579  int ret;
1580  FILE *f;
1581  const char *ext;
1582  LUT1DContext *lut1d = ctx->priv;
1583 
1584  lut1d->scale.r = lut1d->scale.g = lut1d->scale.b = 1.f;
1585 
1586  if (!lut1d->file) {
1587  set_identity_matrix_1d(lut1d, 32);
1588  return 0;
1589  }
1590 
1591  f = fopen(lut1d->file, "r");
1592  if (!f) {
1593  ret = AVERROR(errno);
1594  av_log(ctx, AV_LOG_ERROR, "%s: %s\n", lut1d->file, av_err2str(ret));
1595  return ret;
1596  }
1597 
1598  ext = strrchr(lut1d->file, '.');
1599  if (!ext) {
1600  av_log(ctx, AV_LOG_ERROR, "Unable to guess the format from the extension\n");
1601  ret = AVERROR_INVALIDDATA;
1602  goto end;
1603  }
1604  ext++;
1605 
1606  if (!av_strcasecmp(ext, "cube") || !av_strcasecmp(ext, "1dlut")) {
1607  ret = parse_cube_1d(ctx, f);
1608  } else if (!av_strcasecmp(ext, "csp")) {
1609  ret = parse_cinespace_1d(ctx, f);
1610  } else {
1611  av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext);
1612  ret = AVERROR(EINVAL);
1613  }
1614 
1615  if (!ret && !lut1d->lutsize) {
1616  av_log(ctx, AV_LOG_ERROR, "1D LUT is empty\n");
1617  ret = AVERROR_INVALIDDATA;
1618  }
1619 
1620 end:
1621  fclose(f);
1622  return ret;
1623 }
1624 
1625 static AVFrame *apply_1d_lut(AVFilterLink *inlink, AVFrame *in)
1626 {
1627  AVFilterContext *ctx = inlink->dst;
1628  LUT1DContext *lut1d = ctx->priv;
1629  AVFilterLink *outlink = inlink->dst->outputs[0];
1630  AVFrame *out;
1631  ThreadData td;
1632 
1633  if (av_frame_is_writable(in)) {
1634  out = in;
1635  } else {
1636  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
1637  if (!out) {
1638  av_frame_free(&in);
1639  return NULL;
1640  }
1641  av_frame_copy_props(out, in);
1642  }
1643 
1644  td.in = in;
1645  td.out = out;
1646  ctx->internal->execute(ctx, lut1d->interp, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
1647 
1648  if (out != in)
1649  av_frame_free(&in);
1650 
1651  return out;
1652 }
1653 
1654 static int filter_frame_1d(AVFilterLink *inlink, AVFrame *in)
1655 {
1656  AVFilterLink *outlink = inlink->dst->outputs[0];
1657  AVFrame *out = apply_1d_lut(inlink, in);
1658  if (!out)
1659  return AVERROR(ENOMEM);
1660  return ff_filter_frame(outlink, out);
1661 }
1662 
1663 static const AVFilterPad lut1d_inputs[] = {
1664  {
1665  .name = "default",
1666  .type = AVMEDIA_TYPE_VIDEO,
1667  .filter_frame = filter_frame_1d,
1668  .config_props = config_input_1d,
1669  },
1670  { NULL }
1671 };
1672 
1673 static const AVFilterPad lut1d_outputs[] = {
1674  {
1675  .name = "default",
1676  .type = AVMEDIA_TYPE_VIDEO,
1677  },
1678  { NULL }
1679 };
1680 
1682  .name = "lut1d",
1683  .description = NULL_IF_CONFIG_SMALL("Adjust colors using a 1D LUT."),
1684  .priv_size = sizeof(LUT1DContext),
1685  .init = lut1d_init,
1687  .inputs = lut1d_inputs,
1688  .outputs = lut1d_outputs,
1689  .priv_class = &lut1d_class,
1691 };
1692 #endif
#define NULL
Definition: coverity.c:32
const char const char void * val
Definition: avisynth_c.h:863
#define FRAMESYNC_DEFINE_CLASS(name, context, field)
Definition: framesync.h:300
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
AVFrame * out
Definition: af_adeclick.c:488
#define COMMON_OPTIONS
Definition: vf_lut3d.c:87
static int config_input(AVFilterLink *inlink)
Definition: vf_lut3d.c:712
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2522
This structure describes decoded (raw) audio or video data.
Definition: frame.h:295
AVOption.
Definition: opt.h:246
static struct rgbvec interp_trilinear(const LUT3DContext *lut3d, const struct rgbvec *s)
Interpolate using the 8 vertices of a cube.
Definition: vf_lut3d.c:124
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
#define AV_PIX_FMT_GBRAP10
Definition: pixfmt.h:407
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:182
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2562
Main libavfilter public API header.
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
const char * desc
Definition: nvenc.c:68
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:377
#define a0
Definition: regdef.h:46
planar GBR 4:4:4 24bpp
Definition: pixfmt.h:168
static int skip_line(const char *p)
Definition: vf_lut3d.c:340
#define AV_PIX_FMT_GBRP10
Definition: pixfmt.h:403
static av_const int av_isspace(int c)
Locale-independent conversion of ASCII isspace.
Definition: avstring.h:222
#define AV_PIX_FMT_BGRA64
Definition: pixfmt.h:382
#define a1
Definition: regdef.h:47
static int parse_cube(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:409
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
Definition: framesync.c:117
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
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:283
static int set_identity_matrix(AVFilterContext *ctx, int size)
Definition: vf_lut3d.c:663
#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
Some filters support a generic "enable" expression option that can be used to enable or disable a fil...
Definition: avfilter.h:125
const char * name
Pad name.
Definition: internal.h:60
AVFilterContext * parent
Parent filter context.
Definition: framesync.h:152
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:346
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
#define MAX_LEVEL
Definition: vf_lut3d.c:58
AVFilter ff_vf_haldclut
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1093
#define a3
Definition: regdef.h:49
static float lerpf(float v0, float v1, float f)
Definition: vf_lut3d.c:94
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:82
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:361
filter_frame For filters that do not use the activate() callback
#define f(width, name)
Definition: cbs_vp9.c:255
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1)
Definition: framesync.c:379
#define cosf(x)
Definition: libm.h:78
#define AV_PIX_FMT_GBRP9
Definition: pixfmt.h:402
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
Definition: pixfmt.h:94
Misc file utilities.
#define NEAR(x)
Definition: vf_lut3d.c:107
#define OFFSET(x)
Definition: vf_lut3d.c:85
static const uint64_t c1
Definition: murmur3.c:49
#define AV_PIX_FMT_BGR48
Definition: pixfmt.h:378
struct rgbvec scale
Definition: vf_lut3d.c:67
#define max(a, b)
Definition: cuda_runtime.h:33
static int parse_cinespace(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:570
ptrdiff_t size
Definition: opengl_enc.c:100
#define av_log(a,...)
A filter pad used for either input or output.
Definition: internal.h:54
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
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:569
#define td
Definition: regdef.h:70
uint8_t rgba_map[4]
Definition: vf_lut3d.c:64
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition: framesync.c:293
interp_mode
Definition: vf_lut3d.c:45
#define DEFINE_INTERP_FUNC(name, nbits)
Definition: vf_lut3d.c:288
Frame sync structure.
Definition: framesync.h:146
struct rgbvec * lut
Definition: vf_lut3d.c:68
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:202
#define NEXT(x)
Definition: vf_lut3d.c:109
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
#define MAX_LINE_SIZE
Definition: vf_lut3d.c:338
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
void * priv
private data for use by the filter
Definition: avfilter.h:353
int av_get_padded_bits_per_pixel(const AVPixFmtDescriptor *pixdesc)
Return the number of bits per pixel for the pixel format described by pixdesc, including any padding ...
Definition: pixdesc.c:2487
static struct rgbvec interp_nearest(const LUT3DContext *lut3d, const struct rgbvec *s)
Get the nearest defined point.
Definition: vf_lut3d.c:114
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:116
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
static int config_output(AVFilterLink *outlink)
Definition: af_aecho.c:232
Definition: graph2dot.c:48
#define AV_PIX_FMT_GBRAP12
Definition: pixfmt.h:408
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:373
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:344
#define FLAGS
Definition: vf_lut3d.c:86
#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:409
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 SET_COLOR(id)
uint64_t flags
Combination of AV_PIX_FMT_FLAG_...
Definition: pixdesc.h:106
#define AV_PIX_FMT_GBRP16
Definition: pixfmt.h:406
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:802
int lutsize2
Definition: vf_lut3d.c:70
#define FFMIN(a, b)
Definition: common.h:96
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition: avstring.c:213
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:351
#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:209
int lutsize
Definition: vf_lut3d.c:69
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
int n
Definition: avisynth_c.h:760
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
#define AV_PIX_FMT_GBRP14
Definition: pixfmt.h:405
static AVFrame * apply_lut(AVFilterLink *inlink, AVFrame *in)
Definition: vf_lut3d.c:749
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
int( avfilter_action_func)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
A function pointer passed to the AVFilterGraph::execute callback to be executed multiple times...
Definition: avfilter.h:823
int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
Definition: drawutils.c:35
#define PREV(x)
Definition: vf_lut3d.c:108
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:62
char * file
Definition: vf_lut3d.c:63
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
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:64
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:326
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:81
uint8_t pi<< 24) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_U8,(uint64_t)((*(const uint8_t *) pi-0x80U))<< 56) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8,(*(const uint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8,(*(const uint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16,(*(const int16_t *) pi >>8)+0x80) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S16,(uint64_t)(*(const int16_t *) pi)<< 48) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16,*(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16,*(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32,(*(const int32_t *) pi >>24)+0x80) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S32,(uint64_t)(*(const int32_t *) pi)<< 32) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32,*(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32,*(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S64,(*(const int64_t *) pi >>56)+0x80) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S64,*(const int64_t *) pi *(1.0f/(UINT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S64,*(const int64_t *) pi *(1.0/(UINT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_FLT, llrintf(*(const float *) pi *(UINT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31)))) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_DBL, llrint(*(const double *) pi *(UINT64_C(1)<< 63)))#define FMT_PAIR_FUNC(out, in) static conv_func_type *const fmt_pair_to_conv_functions[AV_SAMPLE_FMT_NB *AV_SAMPLE_FMT_NB]={FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64),};static void cpy1(uint8_t **dst, const uint8_t **src, int len){memcpy(*dst,*src, len);}static void cpy2(uint8_t **dst, const uint8_t **src, int len){memcpy(*dst,*src, 2 *len);}static void cpy4(uint8_t **dst, const uint8_t **src, int len){memcpy(*dst,*src, 4 *len);}static void cpy8(uint8_t **dst, const uint8_t **src, int len){memcpy(*dst,*src, 8 *len);}AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, const int *ch_map, int flags){AudioConvert *ctx;conv_func_type *f=fmt_pair_to_conv_functions[av_get_packed_sample_fmt(out_fmt)+AV_SAMPLE_FMT_NB *av_get_packed_sample_fmt(in_fmt)];if(!f) return NULL;ctx=av_mallocz(sizeof(*ctx));if(!ctx) return NULL;if(channels==1){in_fmt=av_get_planar_sample_fmt(in_fmt);out_fmt=av_get_planar_sample_fmt(out_fmt);}ctx->channels=channels;ctx->conv_f=f;ctx->ch_map=ch_map;if(in_fmt==AV_SAMPLE_FMT_U8||in_fmt==AV_SAMPLE_FMT_U8P) memset(ctx->silence, 0x80, sizeof(ctx->silence));if(out_fmt==in_fmt &&!ch_map){switch(av_get_bytes_per_sample(in_fmt)){case 1:ctx->simd_f=cpy1;break;case 2:ctx->simd_f=cpy2;break;case 4:ctx->simd_f=cpy4;break;case 8:ctx->simd_f=cpy8;break;}}if(HAVE_X86ASM &&1) swri_audio_convert_init_x86(ctx, out_fmt, in_fmt, channels);if(ARCH_ARM) swri_audio_convert_init_arm(ctx, out_fmt, in_fmt, channels);if(ARCH_AARCH64) swri_audio_convert_init_aarch64(ctx, out_fmt, in_fmt, channels);return ctx;}void swri_audio_convert_free(AudioConvert **ctx){av_freep(ctx);}int swri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, int len){int ch;int off=0;const int os=(out->planar?1:out->ch_count)*out->bps;unsigned misaligned=0;av_assert0(ctx->channels==out->ch_count);if(ctx->in_simd_align_mask){int planes=in->planar?in->ch_count:1;unsigned m=0;for(ch=0;ch< planes;ch++) m|=(intptr_t) in->ch[ch];misaligned|=m &ctx->in_simd_align_mask;}if(ctx->out_simd_align_mask){int planes=out->planar?out->ch_count:1;unsigned m=0;for(ch=0;ch< planes;ch++) m|=(intptr_t) out->ch[ch];misaligned|=m &ctx->out_simd_align_mask;}if(ctx->simd_f &&!ctx->ch_map &&!misaligned){off=len &~15;av_assert1(off >=0);av_assert1(off<=len);av_assert2(ctx->channels==SWR_CH_MAX||!in->ch[ctx->channels]);if(off >0){if(out->planar==in->planar){int planes=out->planar?out->ch_count:1;for(ch=0;ch< planes;ch++){ctx->simd_f(out-> ch const uint8_t **in ch off *out planar
Definition: audioconvert.c:56
float b
Definition: vf_lut3d.c:53
static struct rgbvec lerp(const struct rgbvec *v0, const struct rgbvec *v1, float f)
Definition: vf_lut3d.c:99
int interpolation
interp_mode
Definition: vf_lut3d.c:62
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(const int16_t *) pi >> 8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t,*(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t,*(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(const int32_t *) pi >> 24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t,*(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t,*(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31))))#define SET_CONV_FUNC_GROUP(ofmt, ifmt) static void set_generic_function(AudioConvert *ac){}void ff_audio_convert_free(AudioConvert **ac){if(!*ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);}AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, int sample_rate, int apply_map){AudioConvert *ac;int in_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) return NULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method!=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt) > 2){ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc){av_free(ac);return NULL;}return ac;}in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar){ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar?ac->channels:1;}else if(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;else ac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);return ac;}int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in){int use_generic=1;int len=in->nb_samples;int p;if(ac->dc){av_log(ac->avr, AV_LOG_TRACE,"%d samples - audio_convert: %s to %s (dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));return ff_convert_dither(ac-> in
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:144
AVFilter ff_vf_lut3d
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:240
const char * name
Filter name.
Definition: avfilter.h:148
#define AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
Same as AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, except that the filter will have its filter_frame() c...
Definition: avfilter.h:133
static struct rgbvec interp_tetrahedral(const LUT3DContext *lut3d, const struct rgbvec *s)
Tetrahedral interpolation.
Definition: vf_lut3d.c:154
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:350
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:275
#define AV_PIX_FMT_GBRP12
Definition: pixfmt.h:404
#define flags(name, subs,...)
Definition: cbs_av1.c:561
AVFilterInternal * internal
An opaque struct for libavfilter internal use.
Definition: avfilter.h:378
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:309
uint8_t level
Definition: svq3.c:207
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
planar GBRA 4:4:4:4 32bpp
Definition: pixfmt.h:215
#define NEXT_LINE(loop_cond)
Definition: vf_lut3d.c:347
static int parse_m3d(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:501
static const uint64_t c2
Definition: murmur3.c:50
static int parse_3dl(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:466
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_lut3d.c:778
avfilter_execute_func * execute
Definition: internal.h:155
static int parse_dat(AVFilterContext *ctx, FILE *f)
Definition: vf_lut3d.c:374
float r
Definition: vf_lut3d.c:53
static int allocate_3dlut(AVFilterContext *ctx, int lutsize)
Definition: vf_lut3d.c:354
#define AVFILTER_DEFINE_CLASS(fname)
Definition: internal.h:334
A list of supported formats for one end of a filter link.
Definition: formats.h:64
An instance of a filter.
Definition: avfilter.h:338
FILE * out
Definition: movenc.c:54
#define av_freep(p)
#define M_PI
Definition: mathematics.h:52
#define av_malloc_array(a, b)
static int query_formats(AVFilterContext *ctx)
Definition: vf_lut3d.c:688
AVFrame * in
Definition: af_afftdn.c:1082
float g
Definition: vf_lut3d.c:53
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
#define AV_PIX_FMT_FLAG_PLANAR
At least one pixel component is not in the first data plane.
Definition: pixdesc.h:144
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:654
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
avfilter_action_func * interp
Definition: vf_lut3d.c:66