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