Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 2013 Clément Bœsch
  3.  *
  4.  * This file is part of FFmpeg.
  5.  *
  6.  * FFmpeg is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2.1 of the License, or (at your option) any later version.
  10.  *
  11.  * FFmpeg is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with FFmpeg; if not, write to the Free Software
  18.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19.  */
  20.  
  21. /**
  22.  * @file
  23.  * 3D Lookup table filter
  24.  */
  25.  
  26. #include "libavutil/opt.h"
  27. #include "libavutil/file.h"
  28. #include "libavutil/intreadwrite.h"
  29. #include "libavutil/avassert.h"
  30. #include "libavutil/pixdesc.h"
  31. #include "libavutil/avstring.h"
  32. #include "avfilter.h"
  33. #include "drawutils.h"
  34. #include "dualinput.h"
  35. #include "formats.h"
  36. #include "internal.h"
  37. #include "video.h"
  38.  
  39. #define R 0
  40. #define G 1
  41. #define B 2
  42. #define A 3
  43.  
  44. enum interp_mode {
  45.     INTERPOLATE_NEAREST,
  46.     INTERPOLATE_TRILINEAR,
  47.     INTERPOLATE_TETRAHEDRAL,
  48.     NB_INTERP_MODE
  49. };
  50.  
  51. struct rgbvec {
  52.     float r, g, b;
  53. };
  54.  
  55. /* 3D LUT don't often go up to level 32, but it is common to have a Hald CLUT
  56.  * of 512x512 (64x64x64) */
  57. #define MAX_LEVEL 64
  58.  
  59. typedef struct LUT3DContext {
  60.     const AVClass *class;
  61.     int interpolation;          ///<interp_mode
  62.     char *file;
  63.     uint8_t rgba_map[4];
  64.     int step;
  65.     avfilter_action_func *interp;
  66.     struct rgbvec lut[MAX_LEVEL][MAX_LEVEL][MAX_LEVEL];
  67.     int lutsize;
  68. #if CONFIG_HALDCLUT_FILTER
  69.     uint8_t clut_rgba_map[4];
  70.     int clut_step;
  71.     int clut_is16bit;
  72.     int clut_width;
  73.     FFDualInputContext dinput;
  74. #endif
  75. } LUT3DContext;
  76.  
  77. typedef struct ThreadData {
  78.     AVFrame *in, *out;
  79. } ThreadData;
  80.  
  81. #define OFFSET(x) offsetof(LUT3DContext, x)
  82. #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
  83. #define COMMON_OPTIONS \
  84.     { "interp", "select interpolation mode", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=INTERPOLATE_TETRAHEDRAL}, 0, NB_INTERP_MODE-1, FLAGS, "interp_mode" }, \
  85.         { "nearest",     "use values from the nearest defined points",            0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_NEAREST},     INT_MIN, INT_MAX, FLAGS, "interp_mode" }, \
  86.         { "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" }, \
  87.         { "tetrahedral", "interpolate values using a tetrahedron",                0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_TETRAHEDRAL}, INT_MIN, INT_MAX, FLAGS, "interp_mode" }, \
  88.     { NULL }
  89.  
  90. static inline float lerpf(float v0, float v1, float f)
  91. {
  92.     return v0 + (v1 - v0) * f;
  93. }
  94.  
  95. static inline struct rgbvec lerp(const struct rgbvec *v0, const struct rgbvec *v1, float f)
  96. {
  97.     struct rgbvec v = {
  98.         lerpf(v0->r, v1->r, f), lerpf(v0->g, v1->g, f), lerpf(v0->b, v1->b, f)
  99.     };
  100.     return v;
  101. }
  102.  
  103. #define NEAR(x) ((int)((x) + .5))
  104. #define PREV(x) ((int)(x))
  105. #define NEXT(x) (FFMIN((int)(x) + 1, lut3d->lutsize - 1))
  106.  
  107. /**
  108.  * Get the nearest defined point
  109.  */
  110. static inline struct rgbvec interp_nearest(const LUT3DContext *lut3d,
  111.                                            const struct rgbvec *s)
  112. {
  113.     return lut3d->lut[NEAR(s->r)][NEAR(s->g)][NEAR(s->b)];
  114. }
  115.  
  116. /**
  117.  * Interpolate using the 8 vertices of a cube
  118.  * @see https://en.wikipedia.org/wiki/Trilinear_interpolation
  119.  */
  120. static inline struct rgbvec interp_trilinear(const LUT3DContext *lut3d,
  121.                                              const struct rgbvec *s)
  122. {
  123.     const int prev[] = {PREV(s->r), PREV(s->g), PREV(s->b)};
  124.     const int next[] = {NEXT(s->r), NEXT(s->g), NEXT(s->b)};
  125.     const struct rgbvec d = {s->r - prev[0], s->g - prev[1], s->b - prev[2]};
  126.     const struct rgbvec c000 = lut3d->lut[prev[0]][prev[1]][prev[2]];
  127.     const struct rgbvec c001 = lut3d->lut[prev[0]][prev[1]][next[2]];
  128.     const struct rgbvec c010 = lut3d->lut[prev[0]][next[1]][prev[2]];
  129.     const struct rgbvec c011 = lut3d->lut[prev[0]][next[1]][next[2]];
  130.     const struct rgbvec c100 = lut3d->lut[next[0]][prev[1]][prev[2]];
  131.     const struct rgbvec c101 = lut3d->lut[next[0]][prev[1]][next[2]];
  132.     const struct rgbvec c110 = lut3d->lut[next[0]][next[1]][prev[2]];
  133.     const struct rgbvec c111 = lut3d->lut[next[0]][next[1]][next[2]];
  134.     const struct rgbvec c00  = lerp(&c000, &c100, d.r);
  135.     const struct rgbvec c10  = lerp(&c010, &c110, d.r);
  136.     const struct rgbvec c01  = lerp(&c001, &c101, d.r);
  137.     const struct rgbvec c11  = lerp(&c011, &c111, d.r);
  138.     const struct rgbvec c0   = lerp(&c00,  &c10,  d.g);
  139.     const struct rgbvec c1   = lerp(&c01,  &c11,  d.g);
  140.     const struct rgbvec c    = lerp(&c0,   &c1,   d.b);
  141.     return c;
  142. }
  143.  
  144. /**
  145.  * Tetrahedral interpolation. Based on code found in Truelight Software Library paper.
  146.  * @see http://www.filmlight.ltd.uk/pdf/whitepapers/FL-TL-TN-0057-SoftwareLib.pdf
  147.  */
  148. static inline struct rgbvec interp_tetrahedral(const LUT3DContext *lut3d,
  149.                                                const struct rgbvec *s)
  150. {
  151.     const int prev[] = {PREV(s->r), PREV(s->g), PREV(s->b)};
  152.     const int next[] = {NEXT(s->r), NEXT(s->g), NEXT(s->b)};
  153.     const struct rgbvec d = {s->r - prev[0], s->g - prev[1], s->b - prev[2]};
  154.     const struct rgbvec c000 = lut3d->lut[prev[0]][prev[1]][prev[2]];
  155.     const struct rgbvec c111 = lut3d->lut[next[0]][next[1]][next[2]];
  156.     struct rgbvec c;
  157.     if (d.r > d.g) {
  158.         if (d.g > d.b) {
  159.             const struct rgbvec c100 = lut3d->lut[next[0]][prev[1]][prev[2]];
  160.             const struct rgbvec c110 = lut3d->lut[next[0]][next[1]][prev[2]];
  161.             c.r = (1-d.r) * c000.r + (d.r-d.g) * c100.r + (d.g-d.b) * c110.r + (d.b) * c111.r;
  162.             c.g = (1-d.r) * c000.g + (d.r-d.g) * c100.g + (d.g-d.b) * c110.g + (d.b) * c111.g;
  163.             c.b = (1-d.r) * c000.b + (d.r-d.g) * c100.b + (d.g-d.b) * c110.b + (d.b) * c111.b;
  164.         } else if (d.r > d.b) {
  165.             const struct rgbvec c100 = lut3d->lut[next[0]][prev[1]][prev[2]];
  166.             const struct rgbvec c101 = lut3d->lut[next[0]][prev[1]][next[2]];
  167.             c.r = (1-d.r) * c000.r + (d.r-d.b) * c100.r + (d.b-d.g) * c101.r + (d.g) * c111.r;
  168.             c.g = (1-d.r) * c000.g + (d.r-d.b) * c100.g + (d.b-d.g) * c101.g + (d.g) * c111.g;
  169.             c.b = (1-d.r) * c000.b + (d.r-d.b) * c100.b + (d.b-d.g) * c101.b + (d.g) * c111.b;
  170.         } else {
  171.             const struct rgbvec c001 = lut3d->lut[prev[0]][prev[1]][next[2]];
  172.             const struct rgbvec c101 = lut3d->lut[next[0]][prev[1]][next[2]];
  173.             c.r = (1-d.b) * c000.r + (d.b-d.r) * c001.r + (d.r-d.g) * c101.r + (d.g) * c111.r;
  174.             c.g = (1-d.b) * c000.g + (d.b-d.r) * c001.g + (d.r-d.g) * c101.g + (d.g) * c111.g;
  175.             c.b = (1-d.b) * c000.b + (d.b-d.r) * c001.b + (d.r-d.g) * c101.b + (d.g) * c111.b;
  176.         }
  177.     } else {
  178.         if (d.b > d.g) {
  179.             const struct rgbvec c001 = lut3d->lut[prev[0]][prev[1]][next[2]];
  180.             const struct rgbvec c011 = lut3d->lut[prev[0]][next[1]][next[2]];
  181.             c.r = (1-d.b) * c000.r + (d.b-d.g) * c001.r + (d.g-d.r) * c011.r + (d.r) * c111.r;
  182.             c.g = (1-d.b) * c000.g + (d.b-d.g) * c001.g + (d.g-d.r) * c011.g + (d.r) * c111.g;
  183.             c.b = (1-d.b) * c000.b + (d.b-d.g) * c001.b + (d.g-d.r) * c011.b + (d.r) * c111.b;
  184.         } else if (d.b > d.r) {
  185.             const struct rgbvec c010 = lut3d->lut[prev[0]][next[1]][prev[2]];
  186.             const struct rgbvec c011 = lut3d->lut[prev[0]][next[1]][next[2]];
  187.             c.r = (1-d.g) * c000.r + (d.g-d.b) * c010.r + (d.b-d.r) * c011.r + (d.r) * c111.r;
  188.             c.g = (1-d.g) * c000.g + (d.g-d.b) * c010.g + (d.b-d.r) * c011.g + (d.r) * c111.g;
  189.             c.b = (1-d.g) * c000.b + (d.g-d.b) * c010.b + (d.b-d.r) * c011.b + (d.r) * c111.b;
  190.         } else {
  191.             const struct rgbvec c010 = lut3d->lut[prev[0]][next[1]][prev[2]];
  192.             const struct rgbvec c110 = lut3d->lut[next[0]][next[1]][prev[2]];
  193.             c.r = (1-d.g) * c000.r + (d.g-d.r) * c010.r + (d.r-d.b) * c110.r + (d.b) * c111.r;
  194.             c.g = (1-d.g) * c000.g + (d.g-d.r) * c010.g + (d.r-d.b) * c110.g + (d.b) * c111.g;
  195.             c.b = (1-d.g) * c000.b + (d.g-d.r) * c010.b + (d.r-d.b) * c110.b + (d.b) * c111.b;
  196.         }
  197.     }
  198.     return c;
  199. }
  200.  
  201. #define DEFINE_INTERP_FUNC(name, nbits)                                                             \
  202. static int interp_##nbits##_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)         \
  203. {                                                                                                   \
  204.     int x, y;                                                                                       \
  205.     const LUT3DContext *lut3d = ctx->priv;                                                          \
  206.     const ThreadData *td = arg;                                                                     \
  207.     const AVFrame *in  = td->in;                                                                    \
  208.     const AVFrame *out = td->out;                                                                   \
  209.     const int direct = out == in;                                                                   \
  210.     const int step = lut3d->step;                                                                   \
  211.     const uint8_t r = lut3d->rgba_map[R];                                                           \
  212.     const uint8_t g = lut3d->rgba_map[G];                                                           \
  213.     const uint8_t b = lut3d->rgba_map[B];                                                           \
  214.     const uint8_t a = lut3d->rgba_map[A];                                                           \
  215.     const int slice_start = (in->height *  jobnr   ) / nb_jobs;                                     \
  216.     const int slice_end   = (in->height * (jobnr+1)) / nb_jobs;                                     \
  217.     uint8_t       *dstrow = out->data[0] + slice_start * out->linesize[0];                          \
  218.     const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0];                          \
  219.     const float scale = (1. / ((1<<nbits) - 1)) * (lut3d->lutsize - 1);                             \
  220.                                                                                                     \
  221.     for (y = slice_start; y < slice_end; y++) {                                                     \
  222.         uint##nbits##_t *dst = (uint##nbits##_t *)dstrow;                                           \
  223.         const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow;                               \
  224.         for (x = 0; x < in->width * step; x += step) {                                              \
  225.             const struct rgbvec scaled_rgb = {src[x + r] * scale,                                   \
  226.                                               src[x + g] * scale,                                   \
  227.                                               src[x + b] * scale};                                  \
  228.             struct rgbvec vec = interp_##name(lut3d, &scaled_rgb);                                  \
  229.             dst[x + r] = av_clip_uint##nbits(vec.r * (float)((1<<nbits) - 1));                      \
  230.             dst[x + g] = av_clip_uint##nbits(vec.g * (float)((1<<nbits) - 1));                      \
  231.             dst[x + b] = av_clip_uint##nbits(vec.b * (float)((1<<nbits) - 1));                      \
  232.             if (!direct && step == 4)                                                               \
  233.                 dst[x + a] = src[x + a];                                                            \
  234.         }                                                                                           \
  235.         dstrow += out->linesize[0];                                                                 \
  236.         srcrow += in ->linesize[0];                                                                 \
  237.     }                                                                                               \
  238.     return 0;                                                                                       \
  239. }
  240.  
  241. DEFINE_INTERP_FUNC(nearest,     8)
  242. DEFINE_INTERP_FUNC(trilinear,   8)
  243. DEFINE_INTERP_FUNC(tetrahedral, 8)
  244.  
  245. DEFINE_INTERP_FUNC(nearest,     16)
  246. DEFINE_INTERP_FUNC(trilinear,   16)
  247. DEFINE_INTERP_FUNC(tetrahedral, 16)
  248.  
  249. #define MAX_LINE_SIZE 512
  250.  
  251. static int skip_line(const char *p)
  252. {
  253.     while (*p && av_isspace(*p))
  254.         p++;
  255.     return !*p || *p == '#';
  256. }
  257.  
  258. #define NEXT_LINE(loop_cond) do {                           \
  259.     if (!fgets(line, sizeof(line), f)) {                    \
  260.         av_log(ctx, AV_LOG_ERROR, "Unexpected EOF\n");      \
  261.         return AVERROR_INVALIDDATA;                         \
  262.     }                                                       \
  263. } while (loop_cond)
  264.  
  265. /* Basically r g and b float values on each line, with a facultative 3DLUTSIZE
  266.  * directive; seems to be generated by Davinci */
  267. static int parse_dat(AVFilterContext *ctx, FILE *f)
  268. {
  269.     LUT3DContext *lut3d = ctx->priv;
  270.     char line[MAX_LINE_SIZE];
  271.     int i, j, k, size;
  272.  
  273.     lut3d->lutsize = size = 33;
  274.  
  275.     NEXT_LINE(skip_line(line));
  276.     if (!strncmp(line, "3DLUTSIZE ", 10)) {
  277.         size = strtol(line + 10, NULL, 0);
  278.         if (size < 2 || size > MAX_LEVEL) {
  279.             av_log(ctx, AV_LOG_ERROR, "Too large or invalid 3D LUT size\n");
  280.             return AVERROR(EINVAL);
  281.         }
  282.         lut3d->lutsize = size;
  283.         NEXT_LINE(skip_line(line));
  284.     }
  285.     for (k = 0; k < size; k++) {
  286.         for (j = 0; j < size; j++) {
  287.             for (i = 0; i < size; i++) {
  288.                 struct rgbvec *vec = &lut3d->lut[k][j][i];
  289.                 if (k != 0 || j != 0 || i != 0)
  290.                     NEXT_LINE(skip_line(line));
  291.                 if (sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3)
  292.                     return AVERROR_INVALIDDATA;
  293.             }
  294.         }
  295.     }
  296.     return 0;
  297. }
  298.  
  299. /* Iridas format */
  300. static int parse_cube(AVFilterContext *ctx, FILE *f)
  301. {
  302.     LUT3DContext *lut3d = ctx->priv;
  303.     char line[MAX_LINE_SIZE];
  304.     float min[3] = {0.0, 0.0, 0.0};
  305.     float max[3] = {1.0, 1.0, 1.0};
  306.  
  307.     while (fgets(line, sizeof(line), f)) {
  308.         if (!strncmp(line, "LUT_3D_SIZE ", 12)) {
  309.             int i, j, k;
  310.             const int size = strtol(line + 12, NULL, 0);
  311.  
  312.             if (size < 2 || size > MAX_LEVEL) {
  313.                 av_log(ctx, AV_LOG_ERROR, "Too large or invalid 3D LUT size\n");
  314.                 return AVERROR(EINVAL);
  315.             }
  316.             lut3d->lutsize = size;
  317.             for (k = 0; k < size; k++) {
  318.                 for (j = 0; j < size; j++) {
  319.                     for (i = 0; i < size; i++) {
  320.                         struct rgbvec *vec = &lut3d->lut[i][j][k];
  321.  
  322.                         do {
  323.                             NEXT_LINE(0);
  324.                             if (!strncmp(line, "DOMAIN_", 7)) {
  325.                                 float *vals = NULL;
  326.                                 if      (!strncmp(line + 7, "MIN ", 4)) vals = min;
  327.                                 else if (!strncmp(line + 7, "MAX ", 4)) vals = max;
  328.                                 if (!vals)
  329.                                     return AVERROR_INVALIDDATA;
  330.                                 sscanf(line + 11, "%f %f %f", vals, vals + 1, vals + 2);
  331.                                 av_log(ctx, AV_LOG_DEBUG, "min: %f %f %f | max: %f %f %f\n",
  332.                                        min[0], min[1], min[2], max[0], max[1], max[2]);
  333.                                 continue;
  334.                             }
  335.                         } while (skip_line(line));
  336.                         if (sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3)
  337.                             return AVERROR_INVALIDDATA;
  338.                         vec->r *= max[0] - min[0];
  339.                         vec->g *= max[1] - min[1];
  340.                         vec->b *= max[2] - min[2];
  341.                     }
  342.                 }
  343.             }
  344.             break;
  345.         }
  346.     }
  347.     return 0;
  348. }
  349.  
  350. /* Assume 17x17x17 LUT with a 16-bit depth
  351.  * FIXME: it seems there are various 3dl formats */
  352. static int parse_3dl(AVFilterContext *ctx, FILE *f)
  353. {
  354.     char line[MAX_LINE_SIZE];
  355.     LUT3DContext *lut3d = ctx->priv;
  356.     int i, j, k;
  357.     const int size = 17;
  358.     const float scale = 16*16*16;
  359.  
  360.     lut3d->lutsize = size;
  361.     NEXT_LINE(skip_line(line));
  362.     for (k = 0; k < size; k++) {
  363.         for (j = 0; j < size; j++) {
  364.             for (i = 0; i < size; i++) {
  365.                 int r, g, b;
  366.                 struct rgbvec *vec = &lut3d->lut[k][j][i];
  367.  
  368.                 NEXT_LINE(skip_line(line));
  369.                 if (sscanf(line, "%d %d %d", &r, &g, &b) != 3)
  370.                     return AVERROR_INVALIDDATA;
  371.                 vec->r = r / scale;
  372.                 vec->g = g / scale;
  373.                 vec->b = b / scale;
  374.             }
  375.         }
  376.     }
  377.     return 0;
  378. }
  379.  
  380. /* Pandora format */
  381. static int parse_m3d(AVFilterContext *ctx, FILE *f)
  382. {
  383.     LUT3DContext *lut3d = ctx->priv;
  384.     float scale;
  385.     int i, j, k, size, in = -1, out = -1;
  386.     char line[MAX_LINE_SIZE];
  387.     uint8_t rgb_map[3] = {0, 1, 2};
  388.  
  389.     while (fgets(line, sizeof(line), f)) {
  390.         if      (!strncmp(line, "in",  2)) in  = strtol(line + 2, NULL, 0);
  391.         else if (!strncmp(line, "out", 3)) out = strtol(line + 3, NULL, 0);
  392.         else if (!strncmp(line, "values", 6)) {
  393.             const char *p = line + 6;
  394. #define SET_COLOR(id) do {                  \
  395.     while (av_isspace(*p))                  \
  396.         p++;                                \
  397.     switch (*p) {                           \
  398.     case 'r': rgb_map[id] = 0; break;       \
  399.     case 'g': rgb_map[id] = 1; break;       \
  400.     case 'b': rgb_map[id] = 2; break;       \
  401.     }                                       \
  402.     while (*p && !av_isspace(*p))           \
  403.         p++;                                \
  404. } while (0)
  405.             SET_COLOR(0);
  406.             SET_COLOR(1);
  407.             SET_COLOR(2);
  408.             break;
  409.         }
  410.     }
  411.  
  412.     if (in == -1 || out == -1) {
  413.         av_log(ctx, AV_LOG_ERROR, "in and out must be defined\n");
  414.         return AVERROR_INVALIDDATA;
  415.     }
  416.     if (in < 2 || out < 2 ||
  417.         in  > MAX_LEVEL*MAX_LEVEL*MAX_LEVEL ||
  418.         out > MAX_LEVEL*MAX_LEVEL*MAX_LEVEL) {
  419.         av_log(ctx, AV_LOG_ERROR, "invalid in (%d) or out (%d)\n", in, out);
  420.         return AVERROR_INVALIDDATA;
  421.     }
  422.     for (size = 1; size*size*size < in; size++);
  423.     lut3d->lutsize = size;
  424.     scale = 1. / (out - 1);
  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[k][j][i];
  430.                 float val[3];
  431.  
  432.                 NEXT_LINE(0);
  433.                 if (sscanf(line, "%f %f %f", val, val + 1, val + 2) != 3)
  434.                     return AVERROR_INVALIDDATA;
  435.                 vec->r = val[rgb_map[0]] * scale;
  436.                 vec->g = val[rgb_map[1]] * scale;
  437.                 vec->b = val[rgb_map[2]] * scale;
  438.             }
  439.         }
  440.     }
  441.     return 0;
  442. }
  443.  
  444. static void set_identity_matrix(LUT3DContext *lut3d, int size)
  445. {
  446.     int i, j, k;
  447.     const float c = 1. / (size - 1);
  448.  
  449.     lut3d->lutsize = size;
  450.     for (k = 0; k < size; k++) {
  451.         for (j = 0; j < size; j++) {
  452.             for (i = 0; i < size; i++) {
  453.                 struct rgbvec *vec = &lut3d->lut[k][j][i];
  454.                 vec->r = k * c;
  455.                 vec->g = j * c;
  456.                 vec->b = i * c;
  457.             }
  458.         }
  459.     }
  460. }
  461.  
  462. static int query_formats(AVFilterContext *ctx)
  463. {
  464.     static const enum AVPixelFormat pix_fmts[] = {
  465.         AV_PIX_FMT_RGB24,  AV_PIX_FMT_BGR24,
  466.         AV_PIX_FMT_RGBA,   AV_PIX_FMT_BGRA,
  467.         AV_PIX_FMT_ARGB,   AV_PIX_FMT_ABGR,
  468.         AV_PIX_FMT_0RGB,   AV_PIX_FMT_0BGR,
  469.         AV_PIX_FMT_RGB0,   AV_PIX_FMT_BGR0,
  470.         AV_PIX_FMT_RGB48,  AV_PIX_FMT_BGR48,
  471.         AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64,
  472.         AV_PIX_FMT_NONE
  473.     };
  474.     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
  475.     if (!fmts_list)
  476.         return AVERROR(ENOMEM);
  477.     return ff_set_common_formats(ctx, fmts_list);
  478. }
  479.  
  480. static int config_input(AVFilterLink *inlink)
  481. {
  482.     int is16bit = 0;
  483.     LUT3DContext *lut3d = inlink->dst->priv;
  484.     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
  485.  
  486.     switch (inlink->format) {
  487.     case AV_PIX_FMT_RGB48:
  488.     case AV_PIX_FMT_BGR48:
  489.     case AV_PIX_FMT_RGBA64:
  490.     case AV_PIX_FMT_BGRA64:
  491.         is16bit = 1;
  492.     }
  493.  
  494.     ff_fill_rgba_map(lut3d->rgba_map, inlink->format);
  495.     lut3d->step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit);
  496.  
  497. #define SET_FUNC(name) do {                             \
  498.     if (is16bit) lut3d->interp = interp_16_##name;      \
  499.     else         lut3d->interp = interp_8_##name;       \
  500. } while (0)
  501.  
  502.     switch (lut3d->interpolation) {
  503.     case INTERPOLATE_NEAREST:     SET_FUNC(nearest);        break;
  504.     case INTERPOLATE_TRILINEAR:   SET_FUNC(trilinear);      break;
  505.     case INTERPOLATE_TETRAHEDRAL: SET_FUNC(tetrahedral);    break;
  506.     default:
  507.         av_assert0(0);
  508.     }
  509.  
  510.     return 0;
  511. }
  512.  
  513. static AVFrame *apply_lut(AVFilterLink *inlink, AVFrame *in)
  514. {
  515.     AVFilterContext *ctx = inlink->dst;
  516.     LUT3DContext *lut3d = ctx->priv;
  517.     AVFilterLink *outlink = inlink->dst->outputs[0];
  518.     AVFrame *out;
  519.     ThreadData td;
  520.  
  521.     if (av_frame_is_writable(in)) {
  522.         out = in;
  523.     } else {
  524.         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
  525.         if (!out) {
  526.             av_frame_free(&in);
  527.             return NULL;
  528.         }
  529.         av_frame_copy_props(out, in);
  530.     }
  531.  
  532.     td.in  = in;
  533.     td.out = out;
  534.     ctx->internal->execute(ctx, lut3d->interp, &td, NULL, FFMIN(outlink->h, ctx->graph->nb_threads));
  535.  
  536.     if (out != in)
  537.         av_frame_free(&in);
  538.  
  539.     return out;
  540. }
  541.  
  542. static int filter_frame(AVFilterLink *inlink, AVFrame *in)
  543. {
  544.     AVFilterLink *outlink = inlink->dst->outputs[0];
  545.     AVFrame *out = apply_lut(inlink, in);
  546.     if (!out)
  547.         return AVERROR(ENOMEM);
  548.     return ff_filter_frame(outlink, out);
  549. }
  550.  
  551. #if CONFIG_LUT3D_FILTER
  552. static const AVOption lut3d_options[] = {
  553.     { "file", "set 3D LUT file name", OFFSET(file), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
  554.     COMMON_OPTIONS
  555. };
  556.  
  557. AVFILTER_DEFINE_CLASS(lut3d);
  558.  
  559. static av_cold int lut3d_init(AVFilterContext *ctx)
  560. {
  561.     int ret;
  562.     FILE *f;
  563.     const char *ext;
  564.     LUT3DContext *lut3d = ctx->priv;
  565.  
  566.     if (!lut3d->file) {
  567.         set_identity_matrix(lut3d, 32);
  568.         return 0;
  569.     }
  570.  
  571.     f = fopen(lut3d->file, "r");
  572.     if (!f) {
  573.         ret = AVERROR(errno);
  574.         av_log(ctx, AV_LOG_ERROR, "%s: %s\n", lut3d->file, av_err2str(ret));
  575.         return ret;
  576.     }
  577.  
  578.     ext = strrchr(lut3d->file, '.');
  579.     if (!ext) {
  580.         av_log(ctx, AV_LOG_ERROR, "Unable to guess the format from the extension\n");
  581.         ret = AVERROR_INVALIDDATA;
  582.         goto end;
  583.     }
  584.     ext++;
  585.  
  586.     if (!av_strcasecmp(ext, "dat")) {
  587.         ret = parse_dat(ctx, f);
  588.     } else if (!av_strcasecmp(ext, "3dl")) {
  589.         ret = parse_3dl(ctx, f);
  590.     } else if (!av_strcasecmp(ext, "cube")) {
  591.         ret = parse_cube(ctx, f);
  592.     } else if (!av_strcasecmp(ext, "m3d")) {
  593.         ret = parse_m3d(ctx, f);
  594.     } else {
  595.         av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext);
  596.         ret = AVERROR(EINVAL);
  597.     }
  598.  
  599.     if (!ret && !lut3d->lutsize) {
  600.         av_log(ctx, AV_LOG_ERROR, "3D LUT is empty\n");
  601.         ret = AVERROR_INVALIDDATA;
  602.     }
  603.  
  604. end:
  605.     fclose(f);
  606.     return ret;
  607. }
  608.  
  609. static const AVFilterPad lut3d_inputs[] = {
  610.     {
  611.         .name         = "default",
  612.         .type         = AVMEDIA_TYPE_VIDEO,
  613.         .filter_frame = filter_frame,
  614.         .config_props = config_input,
  615.     },
  616.     { NULL }
  617. };
  618.  
  619. static const AVFilterPad lut3d_outputs[] = {
  620.     {
  621.         .name = "default",
  622.         .type = AVMEDIA_TYPE_VIDEO,
  623.     },
  624.     { NULL }
  625. };
  626.  
  627. AVFilter ff_vf_lut3d = {
  628.     .name          = "lut3d",
  629.     .description   = NULL_IF_CONFIG_SMALL("Adjust colors using a 3D LUT."),
  630.     .priv_size     = sizeof(LUT3DContext),
  631.     .init          = lut3d_init,
  632.     .query_formats = query_formats,
  633.     .inputs        = lut3d_inputs,
  634.     .outputs       = lut3d_outputs,
  635.     .priv_class    = &lut3d_class,
  636.     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
  637. };
  638. #endif
  639.  
  640. #if CONFIG_HALDCLUT_FILTER
  641.  
  642. static void update_clut(LUT3DContext *lut3d, const AVFrame *frame)
  643. {
  644.     const uint8_t *data = frame->data[0];
  645.     const int linesize  = frame->linesize[0];
  646.     const int w = lut3d->clut_width;
  647.     const int step = lut3d->clut_step;
  648.     const uint8_t *rgba_map = lut3d->clut_rgba_map;
  649.     const int level = lut3d->lutsize;
  650.  
  651. #define LOAD_CLUT(nbits) do {                                           \
  652.     int i, j, k, x = 0, y = 0;                                          \
  653.                                                                         \
  654.     for (k = 0; k < level; k++) {                                       \
  655.         for (j = 0; j < level; j++) {                                   \
  656.             for (i = 0; i < level; i++) {                               \
  657.                 const uint##nbits##_t *src = (const uint##nbits##_t *)  \
  658.                     (data + y*linesize + x*step);                       \
  659.                 struct rgbvec *vec = &lut3d->lut[i][j][k];              \
  660.                 vec->r = src[rgba_map[0]] / (float)((1<<(nbits)) - 1);  \
  661.                 vec->g = src[rgba_map[1]] / (float)((1<<(nbits)) - 1);  \
  662.                 vec->b = src[rgba_map[2]] / (float)((1<<(nbits)) - 1);  \
  663.                 if (++x == w) {                                         \
  664.                     x = 0;                                              \
  665.                     y++;                                                \
  666.                 }                                                       \
  667.             }                                                           \
  668.         }                                                               \
  669.     }                                                                   \
  670. } while (0)
  671.  
  672.     if (!lut3d->clut_is16bit) LOAD_CLUT(8);
  673.     else                      LOAD_CLUT(16);
  674. }
  675.  
  676.  
  677. static int config_output(AVFilterLink *outlink)
  678. {
  679.     AVFilterContext *ctx = outlink->src;
  680.     LUT3DContext *lut3d = ctx->priv;
  681.     int ret;
  682.  
  683.     outlink->w = ctx->inputs[0]->w;
  684.     outlink->h = ctx->inputs[0]->h;
  685.     outlink->time_base = ctx->inputs[0]->time_base;
  686.     if ((ret = ff_dualinput_init(ctx, &lut3d->dinput)) < 0)
  687.         return ret;
  688.     return 0;
  689. }
  690.  
  691. static int filter_frame_hald(AVFilterLink *inlink, AVFrame *inpicref)
  692. {
  693.     LUT3DContext *s = inlink->dst->priv;
  694.     return ff_dualinput_filter_frame(&s->dinput, inlink, inpicref);
  695. }
  696.  
  697. static int request_frame(AVFilterLink *outlink)
  698. {
  699.     LUT3DContext *s = outlink->src->priv;
  700.     return ff_dualinput_request_frame(&s->dinput, outlink);
  701. }
  702.  
  703. static int config_clut(AVFilterLink *inlink)
  704. {
  705.     int size, level, w, h;
  706.     AVFilterContext *ctx = inlink->dst;
  707.     LUT3DContext *lut3d = ctx->priv;
  708.     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
  709.  
  710.     av_assert0(desc);
  711.  
  712.     lut3d->clut_is16bit = 0;
  713.     switch (inlink->format) {
  714.     case AV_PIX_FMT_RGB48:
  715.     case AV_PIX_FMT_BGR48:
  716.     case AV_PIX_FMT_RGBA64:
  717.     case AV_PIX_FMT_BGRA64:
  718.         lut3d->clut_is16bit = 1;
  719.     }
  720.  
  721.     lut3d->clut_step = av_get_padded_bits_per_pixel(desc) >> 3;
  722.     ff_fill_rgba_map(lut3d->clut_rgba_map, inlink->format);
  723.  
  724.     if (inlink->w > inlink->h)
  725.         av_log(ctx, AV_LOG_INFO, "Padding on the right (%dpx) of the "
  726.                "Hald CLUT will be ignored\n", inlink->w - inlink->h);
  727.     else if (inlink->w < inlink->h)
  728.         av_log(ctx, AV_LOG_INFO, "Padding at the bottom (%dpx) of the "
  729.                "Hald CLUT will be ignored\n", inlink->h - inlink->w);
  730.     lut3d->clut_width = w = h = FFMIN(inlink->w, inlink->h);
  731.  
  732.     for (level = 1; level*level*level < w; level++);
  733.     size = level*level*level;
  734.     if (size != w) {
  735.         av_log(ctx, AV_LOG_WARNING, "The Hald CLUT width does not match the level\n");
  736.         return AVERROR_INVALIDDATA;
  737.     }
  738.     av_assert0(w == h && w == size);
  739.     level *= level;
  740.     if (level > MAX_LEVEL) {
  741.         const int max_clut_level = sqrt(MAX_LEVEL);
  742.         const int max_clut_size  = max_clut_level*max_clut_level*max_clut_level;
  743.         av_log(ctx, AV_LOG_ERROR, "Too large Hald CLUT "
  744.                "(maximum level is %d, or %dx%d CLUT)\n",
  745.                max_clut_level, max_clut_size, max_clut_size);
  746.         return AVERROR(EINVAL);
  747.     }
  748.     lut3d->lutsize = level;
  749.  
  750.     return 0;
  751. }
  752.  
  753. static AVFrame *update_apply_clut(AVFilterContext *ctx, AVFrame *main,
  754.                                   const AVFrame *second)
  755. {
  756.     AVFilterLink *inlink = ctx->inputs[0];
  757.     update_clut(ctx->priv, second);
  758.     return apply_lut(inlink, main);
  759. }
  760.  
  761. static av_cold int haldclut_init(AVFilterContext *ctx)
  762. {
  763.     LUT3DContext *lut3d = ctx->priv;
  764.     lut3d->dinput.process = update_apply_clut;
  765.     return 0;
  766. }
  767.  
  768. static av_cold void haldclut_uninit(AVFilterContext *ctx)
  769. {
  770.     LUT3DContext *lut3d = ctx->priv;
  771.     ff_dualinput_uninit(&lut3d->dinput);
  772. }
  773.  
  774. static const AVOption haldclut_options[] = {
  775.     { "shortest",   "force termination when the shortest input terminates", OFFSET(dinput.shortest),   AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
  776.     { "repeatlast", "continue applying the last clut after eos",            OFFSET(dinput.repeatlast), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, FLAGS },
  777.     COMMON_OPTIONS
  778. };
  779.  
  780. AVFILTER_DEFINE_CLASS(haldclut);
  781.  
  782. static const AVFilterPad haldclut_inputs[] = {
  783.     {
  784.         .name         = "main",
  785.         .type         = AVMEDIA_TYPE_VIDEO,
  786.         .filter_frame = filter_frame_hald,
  787.         .config_props = config_input,
  788.     },{
  789.         .name         = "clut",
  790.         .type         = AVMEDIA_TYPE_VIDEO,
  791.         .filter_frame = filter_frame_hald,
  792.         .config_props = config_clut,
  793.     },
  794.     { NULL }
  795. };
  796.  
  797. static const AVFilterPad haldclut_outputs[] = {
  798.     {
  799.         .name          = "default",
  800.         .type          = AVMEDIA_TYPE_VIDEO,
  801.         .request_frame = request_frame,
  802.         .config_props  = config_output,
  803.     },
  804.     { NULL }
  805. };
  806.  
  807. AVFilter ff_vf_haldclut = {
  808.     .name          = "haldclut",
  809.     .description   = NULL_IF_CONFIG_SMALL("Adjust colors using a Hald CLUT."),
  810.     .priv_size     = sizeof(LUT3DContext),
  811.     .init          = haldclut_init,
  812.     .uninit        = haldclut_uninit,
  813.     .query_formats = query_formats,
  814.     .inputs        = haldclut_inputs,
  815.     .outputs       = haldclut_outputs,
  816.     .priv_class    = &haldclut_class,
  817.     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
  818. };
  819. #endif
  820.