avfilter: add tlut2 filter
authorPaul B Mahol <onemda@gmail.com>
Fri, 4 Aug 2017 08:29:12 +0000 (10:29 +0200)
committerPaul B Mahol <onemda@gmail.com>
Fri, 4 Aug 2017 09:45:08 +0000 (11:45 +0200)
Changelog
doc/filters.texi
libavfilter/Makefile
libavfilter/allfilters.c
libavfilter/version.h
libavfilter/vf_lut2.c

index 3074942..86ce418 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -30,6 +30,7 @@ version <next>:
 - libvmaf video filter
 - Dolby E decoder and SMPTE 337M demuxer
 - unpremultiply video filter
 - libvmaf video filter
 - Dolby E decoder and SMPTE 337M demuxer
 - unpremultiply video filter
+- tlut2 video filter
 
 version 3.3:
 - CrystalHD decoder moved to new decode API
 
 version 3.3:
 - CrystalHD decoder moved to new decode API
index 96abffb..a920bf9 100644 (file)
@@ -9946,9 +9946,13 @@ lutyuv=u='(val-maxval/2)*2+maxval/2':v='(val-maxval/2)*2+maxval/2'
 @end example
 @end itemize
 
 @end example
 @end itemize
 
-@section lut2
+@section lut2, tlut2
 
 
-Compute and apply a lookup table from two video inputs.
+The @code{lut2} filter takes two input streams and outputs one
+stream.
+
+The @code{tlut2} (time lut2) filter takes two consecutive frames
+from one single stream.
 
 This filter accepts the following parameters:
 @table @option
 
 This filter accepts the following parameters:
 @table @option
index f0bb8e7..f615c66 100644 (file)
@@ -312,6 +312,7 @@ OBJS-$(CONFIG_THRESHOLD_FILTER)              += vf_threshold.o framesync2.o
 OBJS-$(CONFIG_THUMBNAIL_FILTER)              += vf_thumbnail.o
 OBJS-$(CONFIG_TILE_FILTER)                   += vf_tile.o
 OBJS-$(CONFIG_TINTERLACE_FILTER)             += vf_tinterlace.o
 OBJS-$(CONFIG_THUMBNAIL_FILTER)              += vf_thumbnail.o
 OBJS-$(CONFIG_TILE_FILTER)                   += vf_tile.o
 OBJS-$(CONFIG_TINTERLACE_FILTER)             += vf_tinterlace.o
+OBJS-$(CONFIG_TLUT2_FILTER)                  += vf_lut2.o framesync2.o
 OBJS-$(CONFIG_TRANSPOSE_FILTER)              += vf_transpose.o
 OBJS-$(CONFIG_TRIM_FILTER)                   += trim.o
 OBJS-$(CONFIG_UNPREMULTIPLY_FILTER)          += vf_premultiply.o framesync2.o
 OBJS-$(CONFIG_TRANSPOSE_FILTER)              += vf_transpose.o
 OBJS-$(CONFIG_TRIM_FILTER)                   += trim.o
 OBJS-$(CONFIG_UNPREMULTIPLY_FILTER)          += vf_premultiply.o framesync2.o
index 0fca662..32f2680 100644 (file)
@@ -323,6 +323,7 @@ static void register_all(void)
     REGISTER_FILTER(THUMBNAIL,      thumbnail,      vf);
     REGISTER_FILTER(TILE,           tile,           vf);
     REGISTER_FILTER(TINTERLACE,     tinterlace,     vf);
     REGISTER_FILTER(THUMBNAIL,      thumbnail,      vf);
     REGISTER_FILTER(TILE,           tile,           vf);
     REGISTER_FILTER(TINTERLACE,     tinterlace,     vf);
+    REGISTER_FILTER(TLUT2,          tlut2,          vf);
     REGISTER_FILTER(TRANSPOSE,      transpose,      vf);
     REGISTER_FILTER(TRIM,           trim,           vf);
     REGISTER_FILTER(UNPREMULTIPLY,  unpremultiply,  vf);
     REGISTER_FILTER(TRANSPOSE,      transpose,      vf);
     REGISTER_FILTER(TRIM,           trim,           vf);
     REGISTER_FILTER(UNPREMULTIPLY,  unpremultiply,  vf);
index 04ea8b7..ff0467c 100644 (file)
@@ -30,8 +30,8 @@
 #include "libavutil/version.h"
 
 #define LIBAVFILTER_VERSION_MAJOR   6
 #include "libavutil/version.h"
 
 #define LIBAVFILTER_VERSION_MAJOR   6
-#define LIBAVFILTER_VERSION_MINOR  96
-#define LIBAVFILTER_VERSION_MICRO 101
+#define LIBAVFILTER_VERSION_MINOR  97
+#define LIBAVFILTER_VERSION_MICRO 100
 
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
                                                LIBAVFILTER_VERSION_MINOR, \
 
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
                                                LIBAVFILTER_VERSION_MINOR, \
index f7e4a6a..0859285 100644 (file)
@@ -61,6 +61,8 @@ typedef struct LUT2Context {
     int width[4], height[4];
     int nb_planes;
     int depth, depthx, depthy;
     int width[4], height[4];
     int nb_planes;
     int depth, depthx, depthy;
+    int tlut2;
+    AVFrame *prev_frame;        /* only used with tlut2 */
 
     void (*lut2)(struct LUT2Context *s, AVFrame *dst, AVFrame *srcx, AVFrame *srcy);
 
 
     void (*lut2)(struct LUT2Context *s, AVFrame *dst, AVFrame *srcx, AVFrame *srcy);
 
@@ -70,7 +72,7 @@ typedef struct LUT2Context {
 #define OFFSET(x) offsetof(LUT2Context, x)
 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
 
 #define OFFSET(x) offsetof(LUT2Context, x)
 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
 
-static const AVOption lut2_options[] = {
+static const AVOption options[] = {
     { "c0", "set component #0 expression", OFFSET(comp_expr_str[0]),  AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS },
     { "c1", "set component #1 expression", OFFSET(comp_expr_str[1]),  AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS },
     { "c2", "set component #2 expression", OFFSET(comp_expr_str[2]),  AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS },
     { "c0", "set component #0 expression", OFFSET(comp_expr_str[0]),  AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS },
     { "c1", "set component #1 expression", OFFSET(comp_expr_str[1]),  AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS },
     { "c2", "set component #2 expression", OFFSET(comp_expr_str[2]),  AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS },
@@ -83,6 +85,8 @@ static av_cold void uninit(AVFilterContext *ctx)
     LUT2Context *s = ctx->priv;
     int i;
 
     LUT2Context *s = ctx->priv;
     int i;
 
+    av_frame_free(&s->prev_frame);
+
     for (i = 0; i < 4; i++) {
         av_expr_free(s->comp_expr[i]);
         s->comp_expr[i] = NULL;
     for (i = 0; i < 4; i++) {
         av_expr_free(s->comp_expr[i]);
         s->comp_expr[i] = NULL;
@@ -133,6 +137,11 @@ static int config_inputx(AVFilterLink *inlink)
     s->depthx = desc->comp[0].depth;
     s->var_values[VAR_BITDEPTHX] = s->depthx;
 
     s->depthx = desc->comp[0].depth;
     s->var_values[VAR_BITDEPTHX] = s->depthx;
 
+    if (s->tlut2) {
+        s->depthy = desc->comp[0].depth;
+        s->var_values[VAR_BITDEPTHY] = s->depthy;
+    }
+
     return 0;
 }
 
     return 0;
 }
 
@@ -232,13 +241,64 @@ static int config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     LUT2Context *s = ctx->priv;
 {
     AVFilterContext *ctx = outlink->src;
     LUT2Context *s = ctx->priv;
-    AVFilterLink *srcx = ctx->inputs[0];
-    AVFilterLink *srcy = ctx->inputs[1];
-    FFFrameSyncIn *in;
     int p, ret;
 
     s->depth = s->depthx + s->depthy;
 
     int p, ret;
 
     s->depth = s->depthx + s->depthy;
 
+    s->lut2 = s->depth > 16 ? lut2_16bit : lut2_8bit;
+
+    for (p = 0; p < s->nb_planes; p++) {
+        s->lut[p] = av_malloc_array(1 << s->depth, sizeof(uint16_t));
+        if (!s->lut[p])
+            return AVERROR(ENOMEM);
+    }
+
+    for (p = 0; p < s->nb_planes; p++) {
+        double res;
+        int x, y;
+
+        /* create the parsed expression */
+        av_expr_free(s->comp_expr[p]);
+        s->comp_expr[p] = NULL;
+        ret = av_expr_parse(&s->comp_expr[p], s->comp_expr_str[p],
+                            var_names, NULL, NULL, NULL, NULL, 0, ctx);
+        if (ret < 0) {
+            av_log(ctx, AV_LOG_ERROR,
+                   "Error when parsing the expression '%s' for the component %d.\n",
+                   s->comp_expr_str[p], p);
+            return AVERROR(EINVAL);
+        }
+
+        /* compute the lut */
+        for (y = 0; y < (1 << s->depthx); y++) {
+            s->var_values[VAR_Y] = y;
+            for (x = 0; x < (1 << s->depthx); x++) {
+                s->var_values[VAR_X] = x;
+                res = av_expr_eval(s->comp_expr[p], s->var_values, s);
+                if (isnan(res)) {
+                    av_log(ctx, AV_LOG_ERROR,
+                           "Error when evaluating the expression '%s' for the values %d and %d for the component %d.\n",
+                           s->comp_expr_str[p], x, y, p);
+                    return AVERROR(EINVAL);
+                }
+
+                s->lut[p][(y << s->depthx) + x] = res;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int lut2_config_output(AVFilterLink *outlink)
+{
+    AVFilterContext *ctx = outlink->src;
+    LUT2Context *s = ctx->priv;
+    AVFilterLink *srcx = ctx->inputs[0];
+    AVFilterLink *srcy = ctx->inputs[1];
+    FFFrameSyncIn *in;
+    int ret;
+
     if (srcx->format != srcy->format) {
         av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n");
         return AVERROR(EINVAL);
     if (srcx->format != srcy->format) {
         av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n");
         return AVERROR(EINVAL);
@@ -281,47 +341,8 @@ static int config_output(AVFilterLink *outlink)
     s->fs.opaque   = s;
     s->fs.on_event = process_frame;
 
     s->fs.opaque   = s;
     s->fs.on_event = process_frame;
 
-    s->lut2 = s->depth > 16 ? lut2_16bit : lut2_8bit;
-
-    for (p = 0; p < s->nb_planes; p++) {
-        s->lut[p] = av_malloc_array(1 << s->depth, sizeof(uint16_t));
-        if (!s->lut[p])
-            return AVERROR(ENOMEM);
-    }
-
-    for (p = 0; p < s->nb_planes; p++) {
-        double res;
-        int x, y;
-
-        /* create the parsed expression */
-        av_expr_free(s->comp_expr[p]);
-        s->comp_expr[p] = NULL;
-        ret = av_expr_parse(&s->comp_expr[p], s->comp_expr_str[p],
-                            var_names, NULL, NULL, NULL, NULL, 0, ctx);
-        if (ret < 0) {
-            av_log(ctx, AV_LOG_ERROR,
-                   "Error when parsing the expression '%s' for the component %d.\n",
-                   s->comp_expr_str[p], p);
-            return AVERROR(EINVAL);
-        }
-
-        /* compute the lut */
-        for (y = 0; y < (1 << s->depthx); y++) {
-            s->var_values[VAR_Y] = y;
-            for (x = 0; x < (1 << s->depthx); x++) {
-                s->var_values[VAR_X] = x;
-                res = av_expr_eval(s->comp_expr[p], s->var_values, s);
-                if (isnan(res)) {
-                    av_log(ctx, AV_LOG_ERROR,
-                           "Error when evaluating the expression '%s' for the values %d and %d for the component %d.\n",
-                           s->comp_expr_str[p], x, y, p);
-                    return AVERROR(EINVAL);
-                }
-
-                s->lut[p][(y << s->depthx) + x] = res;
-            }
-        }
-    }
+    if ((ret = config_output(outlink)) < 0)
+        return ret;
 
     return ff_framesync2_configure(&s->fs);
 }
 
     return ff_framesync2_configure(&s->fs);
 }
@@ -350,11 +371,13 @@ static const AVFilterPad outputs[] = {
     {
         .name          = "default",
         .type          = AVMEDIA_TYPE_VIDEO,
     {
         .name          = "default",
         .type          = AVMEDIA_TYPE_VIDEO,
-        .config_props  = config_output,
+        .config_props  = lut2_config_output,
     },
     { NULL }
 };
 
     },
     { NULL }
 };
 
+#define lut2_options options
+
 AVFILTER_DEFINE_CLASS(lut2);
 
 AVFilter ff_vf_lut2 = {
 AVFILTER_DEFINE_CLASS(lut2);
 
 AVFilter ff_vf_lut2 = {
@@ -369,3 +392,73 @@ AVFilter ff_vf_lut2 = {
     .outputs       = outputs,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
     .outputs       = outputs,
     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
 };
+
+#if CONFIG_TLUT2_FILTER
+
+static av_cold int init(AVFilterContext *ctx)
+{
+    LUT2Context *s = ctx->priv;
+
+    s->tlut2 = !strcmp(ctx->filter->name, "tlut2");
+
+    return 0;
+}
+
+static int tlut2_filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+    LUT2Context *s = inlink->dst->priv;
+    AVFilterLink *outlink = inlink->dst->outputs[0];
+
+    if (s->prev_frame) {
+        AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+        if (!out) {
+            av_frame_free(&s->prev_frame);
+            s->prev_frame = frame;
+            return AVERROR(ENOMEM);
+        }
+        av_frame_copy_props(out, frame);
+        s->lut2(s, out, frame, s->prev_frame);
+        av_frame_free(&s->prev_frame);
+        s->prev_frame = frame;
+        return ff_filter_frame(outlink, out);
+    }
+    s->prev_frame = frame;
+    return 0;
+}
+
+#define tlut2_options options
+
+AVFILTER_DEFINE_CLASS(tlut2);
+
+static const AVFilterPad tlut2_inputs[] = {
+    {
+        .name          = "default",
+        .type          = AVMEDIA_TYPE_VIDEO,
+        .filter_frame  = tlut2_filter_frame,
+        .config_props  = config_inputx,
+    },
+    { NULL }
+};
+
+static const AVFilterPad tlut2_outputs[] = {
+    {
+        .name          = "default",
+        .type          = AVMEDIA_TYPE_VIDEO,
+        .config_props  = config_output,
+    },
+    { NULL }
+};
+
+AVFilter ff_vf_tlut2 = {
+    .name          = "tlut2",
+    .description   = NULL_IF_CONFIG_SMALL("Compute and apply a lookup table from two successive frames."),
+    .priv_size     = sizeof(LUT2Context),
+    .priv_class    = &tlut2_class,
+    .query_formats = query_formats,
+    .init          = init,
+    .uninit        = uninit,
+    .inputs        = tlut2_inputs,
+    .outputs       = tlut2_outputs,
+};
+
+#endif