Subversion Repositories Kolibri OS

Rev

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