[FFmpeg-devel] [PATCH] lavfi: add haldclutsrc filter.

Clément Bœsch ubitux at gmail.com
Thu May 23 18:31:12 CEST 2013


TODO: minor bump

---
Not very useful so far, but you can do stuff like that:

  # generate a "cross curved" hald clut:
  ffmpeg -f lavfi -i haldclutsrc=8 -vf curves=cross_process -frames:v 1 -y clut.png

  # use it with ImageMagick
  convert tests/lena.pnm clut.png -hald-clut lena-clutted.png

Related thread:
http://ffmpeg.org/pipermail/ffmpeg-devel/2013-May/144031.html
---
 doc/filters.texi           |   9 ++-
 libavfilter/Makefile       |   1 +
 libavfilter/allfilters.c   |   1 +
 libavfilter/vsrc_testsrc.c | 136 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 146 insertions(+), 1 deletion(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index 8bb132e..1dadba4 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -7394,10 +7394,12 @@ ffplay -f lavfi life=s=300x200:mold=10:r=60:ratio=0.1:death_color=#C83232:life_c
 @end example
 @end itemize
 
- at section color, nullsrc, rgbtestsrc, smptebars, smptehdbars, testsrc
+ at section color, haldclutsrc, nullsrc, rgbtestsrc, smptebars, smptehdbars, testsrc
 
 The @code{color} source provides an uniformly colored input.
 
+The @code{haldclutsrc} source provides an identity Hald CLUT.
+
 The @code{nullsrc} source returns unprocessed video frames. It is
 mainly useful to be employed in analysis / debugging tools, or as the
 source for filters which ignore the input data.
@@ -7426,6 +7428,11 @@ source. It can be the name of a color (case insensitive match) or a
 0xRRGGBB[AA] sequence, possibly followed by an alpha specifier. The
 default value is "black".
 
+ at item level
+Specify the level of the Hald CLUT, only available in the @code{haldclutsrc}
+source. A level of @code{N} generates a picture of @code{N*N*N} by @code{N*N*N}
+to be used an identity matrix for 3D lookup tables.
+
 @item size, s
 Specify the size of the sourced video, it may be a string of the form
 @var{width}x at var{height}, or the name of a size abbreviation. The
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 6cc2930..37f6979 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -196,6 +196,7 @@ OBJS-$(CONFIG_ZMQ_FILTER)                    += f_zmq.o
 OBJS-$(CONFIG_CELLAUTO_FILTER)               += vsrc_cellauto.o
 OBJS-$(CONFIG_COLOR_FILTER)                  += vsrc_testsrc.o
 OBJS-$(CONFIG_FREI0R_SRC_FILTER)             += vf_frei0r.o
+OBJS-$(CONFIG_HALDCLUTSRC_FILTER)            += vsrc_testsrc.o
 OBJS-$(CONFIG_LIFE_FILTER)                   += vsrc_life.o
 OBJS-$(CONFIG_MANDELBROT_FILTER)             += vsrc_mandelbrot.o
 OBJS-$(CONFIG_MPTESTSRC_FILTER)              += vsrc_mptestsrc.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 0f2442d..075ecca 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -193,6 +193,7 @@ void avfilter_register_all(void)
     REGISTER_FILTER(CELLAUTO,       cellauto,       vsrc);
     REGISTER_FILTER(COLOR,          color,          vsrc);
     REGISTER_FILTER(FREI0R,         frei0r_src,     vsrc);
+    REGISTER_FILTER(HALDCLUTSRC,    haldclutsrc,    vsrc);
     REGISTER_FILTER(LIFE,           life,           vsrc);
     REGISTER_FILTER(MANDELBROT,     mandelbrot,     vsrc);
     REGISTER_FILTER(MPTESTSRC,      mptestsrc,      vsrc);
diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c
index 075026d..0083f12 100644
--- a/libavfilter/vsrc_testsrc.c
+++ b/libavfilter/vsrc_testsrc.c
@@ -71,6 +71,9 @@ typedef struct {
 
     /* only used by rgbtest */
     uint8_t rgba_map[4];
+
+    /* only used by haldclut */
+    int level;
 } TestSourceContext;
 
 #define OFFSET(x) offsetof(TestSourceContext, x)
@@ -269,6 +272,139 @@ AVFilter avfilter_vsrc_color = {
 
 #endif /* CONFIG_COLOR_FILTER */
 
+#if CONFIG_HALDCLUTSRC_FILTER
+
+static const AVOption haldclutsrc_options[] = {
+    { "level", "set level", OFFSET(level), AV_OPT_TYPE_INT, {.i64 = 6}, 2, 8, FLAGS },
+    COMMON_OPTIONS
+    { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(haldclutsrc);
+
+static void haldclutsrc_fill_picture(AVFilterContext *ctx, AVFrame *frame)
+{
+    int i, j, k, x = 0, y = 0, is16bit = 0, step;
+    uint32_t alpha = 0;
+    const TestSourceContext *s = ctx->priv;
+    int level = s->level;
+    float scale;
+    const int w = frame->width;
+    const int h = frame->height;
+    const uint8_t *data = frame->data[0];
+    const int linesize  = frame->linesize[0];
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
+    uint8_t rgba_map[4];
+
+    av_assert0(w == h && w == level*level*level);
+
+    ff_fill_rgba_map(rgba_map, frame->format);
+
+    switch (frame->format) {
+    case AV_PIX_FMT_RGB48:
+    case AV_PIX_FMT_BGR48:
+    case AV_PIX_FMT_RGBA64:
+    case AV_PIX_FMT_BGRA64:
+        is16bit = 1;
+        alpha = 0xfffff;
+        break;
+    case AV_PIX_FMT_RGBA:
+    case AV_PIX_FMT_BGRA:
+    case AV_PIX_FMT_ARGB:
+    case AV_PIX_FMT_ABGR:
+        alpha = 0xff;
+        break;
+    }
+
+    step  = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit);
+    scale = ((float)(1 << (8*(is16bit+1))) - 1) / (level*level - 1);
+
+#define LOAD_CLUT(nbits) do {                                                   \
+    uint##nbits##_t *dst = ((uint##nbits##_t *)(data + y*linesize)) + x*step;   \
+    dst[rgba_map[0]] = av_clip_uint##nbits(i * scale);                          \
+    dst[rgba_map[1]] = av_clip_uint##nbits(j * scale);                          \
+    dst[rgba_map[2]] = av_clip_uint##nbits(k * scale);                          \
+    if (step == 4)                                                              \
+        dst[rgba_map[3]] = alpha;                                               \
+} while (0)
+
+    level *= level;
+    for (k = 0; k < level; k++) {
+        for (j = 0; j < level; j++) {
+            for (i = 0; i < level; i++) {
+                if (!is16bit)
+                    LOAD_CLUT(8);
+                else
+                    LOAD_CLUT(16);
+                if (++x == w) {
+                    x = 0;
+                    y++;
+                }
+            }
+        }
+    }
+}
+
+static av_cold int haldclutsrc_init(AVFilterContext *ctx)
+{
+    TestSourceContext *s = ctx->priv;
+    s->fill_picture_fn = haldclutsrc_fill_picture;
+    s->draw_once = 1;
+    return init(ctx);
+}
+
+static int haldclutsrc_query_formats(AVFilterContext *ctx)
+{
+    static const enum AVPixelFormat pix_fmts[] = {
+        AV_PIX_FMT_RGB24,  AV_PIX_FMT_BGR24,
+        AV_PIX_FMT_RGBA,   AV_PIX_FMT_BGRA,
+        AV_PIX_FMT_ARGB,   AV_PIX_FMT_ABGR,
+        AV_PIX_FMT_0RGB,   AV_PIX_FMT_0BGR,
+        AV_PIX_FMT_RGB0,   AV_PIX_FMT_BGR0,
+        AV_PIX_FMT_RGB48,  AV_PIX_FMT_BGR48,
+        AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64,
+        AV_PIX_FMT_NONE,
+    };
+    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+    return 0;
+}
+
+static int haldclutsrc_config_props(AVFilterLink *outlink)
+{
+    AVFilterContext *ctx = outlink->src;
+    TestSourceContext *s = ctx->priv;
+
+    if (outlink->w || outlink->h) {
+        av_log(ctx, AV_LOG_ERROR, "output size must be configured with a level option\n");
+        return AVERROR(EINVAL);
+    }
+    s->w = s->h = s->level * s->level * s->level;
+    return config_props(outlink);
+}
+
+static const AVFilterPad haldclutsrc_outputs[] = {
+    {
+        .name          = "default",
+        .type          = AVMEDIA_TYPE_VIDEO,
+        .request_frame = request_frame,
+        .config_props  = haldclutsrc_config_props,
+    },
+    {  NULL }
+};
+
+AVFilter avfilter_vsrc_haldclutsrc = {
+    .name            = "haldclutsrc",
+    .description     = NULL_IF_CONFIG_SMALL("Provide an identity Hald CLUT."),
+    .priv_class      = &haldclutsrc_class,
+    .priv_size       = sizeof(TestSourceContext),
+    .init            = haldclutsrc_init,
+    .uninit          = uninit,
+    .query_formats   = haldclutsrc_query_formats,
+    .inputs          = NULL,
+    .outputs         = haldclutsrc_outputs,
+};
+#endif /* CONFIG_HALDCLUTSRC_FILTER */
+
 #if CONFIG_NULLSRC_FILTER
 
 #define nullsrc_options options
-- 
1.8.2.3



More information about the ffmpeg-devel mailing list