Hi,

A lot of image operations like gamma adjustment, color inversion or
contrast enhancement can be expressed as a simple function applied 
to each pixel. I have written a YUV(A) only filter to apply these
functions.

For example: color inversion becomes applyfn=255-Y:255-U:255-V.
If the pow function would be available a gamma correction would 
look like this: applyfn=255*pow(Y/255\,0.25):U:V

Zeger Knops
Index: Makefile
===================================================================
--- Makefile    (revision 4305)
+++ Makefile    (working copy)
@@ -14,6 +14,7 @@
        parseutils.o \
 
 
+OBJS-$(CONFIG_APPLYFN_FILTER)    += vf_applyfn.o
 OBJS-$(CONFIG_CROP_FILTER)       += vf_crop.o
 OBJS-$(CONFIG_DRAWBOX_FILTER)    += vf_drawbox.o
 OBJS-$(CONFIG_FPS_FILTER)        += vf_fps.o
Index: allfilters.c
===================================================================
--- allfilters.c    (revision 4305)
+++ allfilters.c    (working copy)
@@ -34,6 +34,7 @@
         return;
     initialized = 1;
 
+    REGISTER_FILTER(APPLYFN,applyfn,vf);
     REGISTER_FILTER(CROP,crop,vf);
     REGISTER_FILTER(DRAWBOX,drawbox,vf);
     REGISTER_FILTER(FIFO,fifo,vf);
Index: vf_applyfn.c
===================================================================
--- vf_applyfn.c    (revision 0)
+++ vf_applyfn.c    (revision 0)
@@ -0,0 +1,227 @@
+/*
+ * applyfn filter
+ * copyright (c) 2009 Zeger Knops
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * Assume pow is available
+ * Gamma(g): applyfn=255*pow(Y/255\,g):U:V
+ *
+ * Assume the floor fn is available we can draw cartoons:
+ * applyfn=floor(Y/64)*64:floor(U/64)*64:floor(V/64)*64
+ *
+ * Assume the modulo fn is availabvle we can draw checkerboars
+ * applyfn=(modulo(floor(x/64)\,2)+modulo(floor(y/64)\,2))*Y
+ *
+ * B&W
+ * applyfn=Y:128:128
+ */
+
+#include "libavcodec/eval.h"
+#include "avfilter.h"
+#include "libavutil/avstring.h"
+
+enum PosOfValue {
+    POV_PI,
+    POV_E,
+    POV_N,
+    POV_W,
+    POV_H,
+    POV_x,
+    POV_y,
+    POV_Y,
+    POV_U,
+    POV_V,
+    POV_A,
+    POV_NULL
+};
+
+static const char *applyfn_symbols[POV_NULL+1]={
+    "PI",
+    "E",
+    "N",         ///< frame number (starting at zero)
+    "W",         ///< frame width
+    "H",         ///< frame height
+    "x",         ///< x position of current pixel
+    "y",         ///< y position of current pixel
+    "Y",         ///< Y value of current pixel
+    "U",         ///< U value of current pixel
+    "V",         ///< V value of current pixel
+    "A",         ///< A value of current pixel
+    NULL
+};
+
+typedef struct
+{
+    AVEvalExpr *value_Y, *value_U, *value_V, *value_A;
+    int hsub, vsub;
+    double values[POV_NULL+1];
+} ApplyfnContext;
+
+static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
+{
+        ApplyfnContext *applyfn = ctx->priv;
+        char Y_expr[256], U_expr[256], V_expr[256], A_expr[256];
+       const char *error;
+
+       applyfn->values[POV_PI      ] = M_PI;
+       applyfn->values[POV_E       ] = M_E;
+       applyfn->values[POV_N       ] = 0.0;
+       applyfn->values[POV_NULL    ] = 0.0;
+
+       av_strlcpy(Y_expr, "Y", sizeof(Y_expr));
+        av_strlcpy(U_expr, "U", sizeof(U_expr));
+        av_strlcpy(V_expr, "V", sizeof(V_expr));
+        av_strlcpy(A_expr, "A", sizeof(V_expr));
+
+       if (args)
+           sscanf(args, "%255[^:]:%255[^:]:%255[^:]:%255[^:]", Y_expr, U_expr, V_expr, A_expr)
+
+       applyfn->value_Y = ff_parse(Y_expr, applyfn_symbols,
+                               NULL, NULL, NULL, NULL, &error);
+       if (!applyfn->value_Y )
+           av_log(ctx, AV_LOG_ERROR,
+                  "init() cannot parse Y expression due to %s\n", error);
+
+        applyfn->value_U = ff_parse(U_expr, applyfn_symbols,
+                                NULL, NULL, NULL, NULL, &error);
+        if (!applyfn->value_U )
+            av_log(ctx, AV_LOG_ERROR,
+                   "init() cannot parse U expression due to %s\n", error);
+
+        applyfn->value_V = ff_parse(V_expr, applyfn_symbols,
+                                NULL, NULL, NULL, NULL, &error);
+        if (!applyfn->value_V )
+            av_log(ctx, AV_LOG_ERROR,
+                   "init() cannot parse V expression due to %s\n", error);
+
+        applyfn->value_A = ff_parse(A_expr, applyfn_symbols,
+                                NULL, NULL, NULL, NULL, &error);
+        if (!applyfn->value_A )
+            av_log(ctx, AV_LOG_ERROR,
+                   "init() cannot parse A expression due to %s\n", error);
+
+   return !applyfn->value_Y || !applyfn->value_U || !applyfn->value_V || !applyfn->value_A;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+    avfilter_set_common_formats(ctx,
+        avfilter_make_format_list(10,
+                PIX_FMT_YUV444P,  PIX_FMT_YUV422P,  PIX_FMT_YUV420P,
+                PIX_FMT_YUV411P,  PIX_FMT_YUV410P,
+                PIX_FMT_YUVJ444P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ420P,
+                PIX_FMT_YUV440P,  PIX_FMT_YUVJ440P,
+                PIX_FMT_YUVA420P));
+    return 0;
+}
+
+static int config_props(AVFilterLink *link)
+{
+    ApplyfnContext *applyfn = link->dst->priv;
+
+    avcodec_get_chroma_sub_sample(link->format, &applyfn->hsub, &applyfn->vsub);
+
+    return 0;
+}
+
+static void draw_slice(AVFilterLink *link, int y, int h)
+{
+    ApplyfnContext *applyfn = link->dst->priv;
+    AVFilterPicRef *in  = link->cur_pic;
+    AVFilterPicRef *out = link->dst->outputs[0]->outpic;
+    uint8_t *inrow_0, *outrow_0, *alpharow, *outrow_1, *outrow_2, *inrow_1, *inrow_2;
+    int i, j, i_sub, j_sub, outrow_1_off, outrow_2_off, inrow_1_off, inrow_2_off;
+
+    applyfn->values[POV_N] += 1.0;
+    applyfn->values[POV_W] = link->w;
+    applyfn->values[POV_H] = h;
+
+    inrow_0  = in-> data[0] + y * in-> linesize[0];
+    outrow_0 = out->data[0] + y * out->linesize[0];
+
+    outrow_1_off = (y >> applyfn->vsub)  * out->linesize[1];
+    outrow_2_off = (h >> applyfn->vsub ) * out->linesize[2] * ( link->w >> applyfn->hsub ) * (y >> applyfn->vsub);
+    inrow_1_off  = (y >> applyfn->vsub)  * in-> linesize[1];
+    inrow_2_off  = (h >> applyfn->vsub ) * in-> linesize[2] * ( link->w >> applyfn->hsub ) * (y >> applyfn->vsub);
+
+    outrow_1 = outrow_1_off + out->data[1];
+    outrow_2 = outrow_2_off + out->data[2];
+    inrow_1  = outrow_1_off + in-> data[1];
+    inrow_2  = outrow_2_off + in-> data[2];
+
+    for(i = 0; i < h; i ++) {
+        applyfn->values[POV_y] = i;
+       i_sub = i >> applyfn->hsub;
+        for(j = 0; j < link->w; j ++)
+        {
+           j_sub = j >> applyfn->hsub;
+
+            applyfn->values[POV_x] = j;
+
+            applyfn->values[POV_Y] = inrow_0[j];
+            applyfn->values[POV_U] = inrow_1[j_sub];
+            applyfn->values[POV_V] = inrow_2[j_sub];
+
+            applyfn->values[POV_A] = out->data[3] ? alpharow[j] : 0;
+
+            outrow_0[j]     = ff_parse_eval(applyfn->value_Y, applyfn->values, applyfn);
+            outrow_1[j_sub] = ff_parse_eval(applyfn->value_U, applyfn->values, applyfn);
+            outrow_2[j_sub] = ff_parse_eval(applyfn->value_V, applyfn->values, applyfn);
+
+            if ( out->data[3] )
+                alpharow[j] = ff_parse_eval(applyfn->value_A, applyfn->values, applyfn);
+
+        }
+        inrow_0  += in-> linesize[0];
+        outrow_0 += out->linesize[0];
+
+        if ( out->data[3] )
+            alpharow += out->linesize[3];
+
+        inrow_1  = inrow_1_off  + in-> data[1] + i_sub * in-> linesize[1];
+        inrow_2  = inrow_2_off  + in-> data[2] + i_sub * in-> linesize[2];
+        outrow_1 = outrow_1_off + out->data[1] + i_sub * out->linesize[1];
+        outrow_2 = outrow_2_off + out->data[2] + i_sub * out->linesize[2];
+    }
+
+    avfilter_draw_slice(link->dst->outputs[0], y, h);
+}
+
+AVFilter avfilter_vf_applyfn =
+{
+    .name      = "applyfn",
+
+    .init      = init,
+
+    .priv_size = sizeof(ApplyfnContext),
+
+    .query_formats = query_formats,
+
+    .inputs    = (AVFilterPad[]) {{ .name            = "default",
+                                    .type            = CODEC_TYPE_VIDEO,
+                                    .draw_slice      = draw_slice,
+                                    .config_props    = config_props,
+                                    .min_perms       = AV_PERM_READ, },
+                                  { .name = NULL}},
+    .outputs   = (AVFilterPad[]) {{ .name            = "default",
+                                    .type            = CODEC_TYPE_VIDEO, },
+                                  { .name = NULL}},
+};
+
_______________________________________________
FFmpeg-soc mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-soc

Reply via email to