Hi,

I've switched to another mailer which shouldn't break threads.

On Tue, 2009-05-26 at 00:58 +0200, Stefano Sabatini wrote:
> > > Docs and example go to doc/vfilters.texi. 
> > 
> > Removed them.
> 
> Uh, what about to move them to doc/vfilters.texi?

Added to the patch.

> > > And a PTS var may be useful too. 
> > > 
> > 
> > Working on that.

pts has been added.
 
> > For some functions it would be much easier to normalize the YUV values
> > to [0.0..1.0][-0.5..0.5][-0.5..0.5] beforehand, would it be an addition 
> > if this were to be an option? 
> 
> Yes, I believe so. Maybe simply adding some vars for the normalized
> values will be fine.

Wouldn't adding the vars make things tricky when evaluating the
expression? How would the expression Y=pow(Yn,0.25)+Y (where Yn is Y
normalized) be evaluated?

> Some nits:
> 
> > +    if ( out->data[3] )
> 
> I believe (out->data[3]) style is preferred.
> 
> > +        alpharow = out->data[3] + y * out->linesize[3];
> > +
> > +    for(i = 0; i < h; i ++) {
> > +        applyfn->var_values[y] = i;
> > +        i_sub = i >> applyfn->hsub;
> > +        for(j = 0; j < link->w; j ++)
> > +        {
> > +           j_sub = j >> applyfn->hsub;
> 
> Not K&R style (for brace not on the same line as the for), and weird
> indent.
> 
> > +            applyfn->var_values[x] = j;
> > +
> > +            applyfn->var_values[Y] = inrow_0[j];
> > +            applyfn->var_values[U] = inrow_1[j_sub];
> > +            applyfn->var_values[V] = inrow_2[j_sub];
> > +
> > +            applyfn->var_values[A] = out->data[3] ? alpharow[j] : 0;
> > +
> > +            outrow_0[j]     = ff_parse_eval(applyfn->Y_evalexpr, 
> > applyfn->var_values, applyfn);
> > +            outrow_1[j_sub] = ff_parse_eval(applyfn->U_evalexpr, 
> > applyfn->var_values, applyfn);
> > +            outrow_2[j_sub] = ff_parse_eval(applyfn->V_evalexpr, 
> > applyfn->var_values, applyfn);
> > +
> > +            if ( out->data[3] )
>                   ^^^^^^^^^^^^^^^^
> > +                alpharow[j] = ff_parse_eval(applyfn->A_evalexpr, 
> > applyfn->var_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,
> 

Updated to K&R style.

> Rethinking at it, I wrote a very similar filter named vf_eval.c but
> which worked in the RGB colorspace.
> 
> Maybe it would be less confusing for the users to give to this filters
> some related names, for example:
> rgbeval and yuveval,
> or
> yuvapplyfn and rgbapplyfn.
> 
> If you don't mind consider to change accordingly the name of the
> filter (but await for others devs opinion, Vitor?).

I don't mind renaming the filter. 

The filter has been updated to support remapping of x and y, so
flipping the video can be done with applyfn="x_exp=W-x" or
apply="x_exp=H-y". A cheesy water effect is achieved with
applyfn="x_exp=x+10*sin((y/H)*PI*10+(N/4))". 

Thanks for the feedback,

Zeger Knops
Index: vf_applyfn.c
===================================================================
--- vf_applyfn.c    (revision 0)
+++ vf_applyfn.c    (revision 0)
@@ -0,0 +1,265 @@
+/*
+ * 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
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "avfilter.h"
+#include "parseutils.h"
+#include "libavcodec/eval.h"
+
+enum VarName {
+    PI,
+    E,
+    N,
+    W,
+    H,
+    pts,
+    x,
+    y,
+    Y,
+    U,
+    V,
+    A,
+    VARS_NB
+};
+
+static const char *var_names[]={
+    "PI",
+    "E",
+    "N",         ///< frame number (starting at zero)
+    "W",         ///< frame width
+    "H",         ///< frame height
+    "pts",       ///< pts of frame
+    "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
+{
+    const AVClass *class;
+    char *Y_expr, *U_expr, *V_expr, *A_expr,
+         *x_expr, *y_expr;
+    AVEvalExpr *Y_evalexpr, *U_evalexpr, *V_evalexpr, *A_evalexpr,
+               *x_evalexpr, *y_evalexpr;
+    int hsub, vsub, ks;
+    double var_values[VARS_NB];
+
+    int8_t *data[4];
+} ApplyfnContext;
+
+#define OFFSET(x) offsetof(ApplyfnContext, x)
+
+#define FF_PARSE( c ) \
+    applyfn->c##_evalexpr = ff_parse((expr = applyfn->c##_expr),\
+                            var_names,\
+                            NULL, NULL, NULL, NULL, &error);\
+    if (error)\
+        goto fail;
+
+static const AVOption applyfn_options[] = {
+{"Y_exp",  "set Y expression", OFFSET(Y_expr),  FF_OPT_TYPE_STRING, 0, CHAR_MIN, CHAR_MAX},
+{"U_exp",  "set U expression", OFFSET(U_expr),  FF_OPT_TYPE_STRING, 0, CHAR_MIN, CHAR_MAX},
+{"V_exp",  "set V expression", OFFSET(V_expr),  FF_OPT_TYPE_STRING, 0, CHAR_MIN, CHAR_MAX},
+{"A_exp",  "set A expression", OFFSET(A_expr),  FF_OPT_TYPE_STRING, 0, CHAR_MIN, CHAR_MAX},
+{"x_exp",  "set x expression", OFFSET(x_expr),  FF_OPT_TYPE_STRING, 0, CHAR_MIN, CHAR_MAX},
+{"y_exp",  "set y expression", OFFSET(y_expr),  FF_OPT_TYPE_STRING, 0, CHAR_MIN, CHAR_MAX},
+{NULL},
+};
+
+static const char *applyfn_get_name(void *ctx) {
+    return "applyfn";
+}
+
+static const AVClass applyfn_class = {
+    "ApplyfnContext",
+    applyfn_get_name,
+    applyfn_options
+};
+
+static int init(AVFilterContext *ctx, const char *args, void *opaque) {
+    ApplyfnContext *applyfn = ctx->priv;
+    const char *error = NULL, *expr;
+
+    applyfn->class = &applyfn_class;
+    av_opt_set_defaults2(applyfn, 0, 0);
+
+    applyfn->var_values[PI] = M_PI;
+    applyfn->var_values[E ] = M_E;
+
+    applyfn->Y_expr = av_strdup("Y");
+    applyfn->U_expr = av_strdup("U");
+    applyfn->V_expr = av_strdup("V");
+    applyfn->A_expr = av_strdup("A");
+
+    applyfn->x_expr = av_strdup("x");
+    applyfn->y_expr = av_strdup("y");
+
+    if (args && av_set_options_string(applyfn, args, "=", ":") < 0)
+        return -1;
+
+    FF_PARSE( Y  );
+    FF_PARSE( U  );
+    FF_PARSE( V  );
+    FF_PARSE( A  );
+    FF_PARSE( x  );
+    FF_PARSE( y  );
+
+    return 0;
+
+fail:
+    av_log(applyfn, AV_LOG_ERROR, "Error when evaluating the expression '%s': %s\n", expr, error);
+    return -1;
+}
+
+static av_cold void uninit(AVFilterContext *ctx) {
+    ApplyfnContext *applyfn = ctx->priv;
+
+    av_free(applyfn->Y_expr);
+    av_free(applyfn->U_expr);
+    av_free(applyfn->V_expr);
+    av_free(applyfn->A_expr);
+    av_free(applyfn->x_expr);
+    av_free(applyfn->y_expr);
+}
+
+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_input(AVFilterLink *link) {
+    ApplyfnContext *applyfn = link->dst->priv;
+
+    avcodec_get_chroma_sub_sample(link->format, &applyfn->hsub, &applyfn->vsub);
+
+    return 0;
+}
+
+static void start_frame(AVFilterLink *link, AVFilterPicRef *picref) {
+    ApplyfnContext *applyfn = link->dst->priv;
+
+    applyfn->var_values[N]  += 1.0;
+    applyfn->var_values[pts] = picref->pts;
+    applyfn->var_values[W]   = link->w;
+    applyfn->var_values[H]   = link->h;
+
+    avfilter_start_frame(link->dst->outputs[0], picref);
+}
+
+static void end_frame(AVFilterLink *link) {
+    avfilter_end_frame(link->dst->outputs[0]);
+}
+
+static void draw_slice(AVFilterLink *link, int ys, int h) {
+    ApplyfnContext *applyfn = link->dst->priv;
+    AVFilterPicRef *in  = link->cur_pic;
+    AVFilterPicRef *out = link->dst->outputs[0]->outpic;
+    uint8_t *outrow_0, *outrow_1, *outrow_2, *alpharow;
+    uint16_t x_eval, y_eval;
+    int outrow_1_off, outrow_2_off, inrow_0_off, inrow_1_off, inrow_2_off, inrow_3_off;
+    int i, j, i_sub, j_sub;
+
+    outrow_1_off = out->data[1] + (ys >> applyfn->vsub) * out->linesize[1];
+    outrow_2_off = out->data[2] + (ys >> applyfn->vsub) * out->linesize[2] * (link->w >> applyfn->hsub) * (h  >> applyfn->vsub);
+
+    inrow_0_off = in->data[0] +  ys                   * in->linesize[0];
+    inrow_1_off = in->data[1] + (ys >> applyfn->vsub) * in->linesize[1];
+    inrow_2_off = in->data[2] + (ys >> applyfn->vsub) * in->linesize[2] * (link->w >> applyfn->hsub) * (h >> applyfn->vsub) ;
+
+    outrow_0 = out->data[0] + ys * out->linesize[0];
+
+    if (out->data[3])
+    {
+        inrow_3_off = in-> data[3] + ys * in-> linesize[3];
+        alpharow    = out->data[3] + ys * out->linesize[3];
+    }
+
+    for(i = 0; i < h; i ++) {
+        applyfn->var_values[y] = i;
+        i_sub = i >> applyfn->hsub;
+
+        outrow_1 = outrow_1_off + i_sub * out->linesize[1];
+        outrow_2 = outrow_2_off + i_sub * out->linesize[2];
+
+        for(j = 0; j < link->w; j ++) {
+            j_sub = j >> applyfn->hsub;
+            applyfn->var_values[x] = j;
+
+            x_eval = (uint16_t) ff_parse_eval(applyfn->x_evalexpr, applyfn->var_values, applyfn) % link->w;
+            y_eval = (uint16_t) ff_parse_eval(applyfn->y_evalexpr, applyfn->var_values, applyfn) % h;
+
+            applyfn->var_values[Y] = *(inrow_0_off +  y_eval                   * in-> linesize[0] +  x_eval);
+            applyfn->var_values[U] = *(inrow_1_off + (y_eval >> applyfn->hsub) * in-> linesize[1] + (x_eval >> applyfn->hsub));
+            applyfn->var_values[V] = *(inrow_2_off + (y_eval >> applyfn->hsub) * in-> linesize[2] + (x_eval >> applyfn->hsub));
+            applyfn->var_values[A] = out->data[3] ?
+                                     *(inrow_3_off +  y_eval                   * in-> linesize[3] +  x_eval): 0;
+
+            outrow_0[j]     = ff_parse_eval(applyfn->Y_evalexpr, applyfn->var_values, applyfn);
+            outrow_1[j_sub] = ff_parse_eval(applyfn->U_evalexpr, applyfn->var_values, applyfn);
+            outrow_2[j_sub] = ff_parse_eval(applyfn->V_evalexpr, applyfn->var_values, applyfn);
+
+            if (out->data[3])
+                alpharow[j] = ff_parse_eval(applyfn->A_evalexpr, applyfn->var_values, applyfn);
+
+        }
+        outrow_0 += out->linesize[0];
+
+        if (out->data[3])
+            alpharow += out->linesize[3];
+    }
+
+    avfilter_draw_slice(link->dst->outputs[0], ys, h);
+}
+
+AVFilter avfilter_vf_applyfn =
+{
+    .name      = "applyfn",
+    .init      = init,
+    .priv_size = sizeof(ApplyfnContext),
+    .init          = init,
+    .uninit        = uninit,
+    .query_formats = query_formats,
+
+    .inputs    = (AVFilterPad[]) {{ .name            = "default",
+                                    .type            = CODEC_TYPE_VIDEO,
+                                    .draw_slice      = draw_slice,
+                                    .start_frame     = start_frame,
+                                    .end_frame       = end_frame,
+                                    .config_props    = config_input, },
+                                  { .name = NULL}},
+    .outputs   = (AVFilterPad[]) {{ .name            = "default",
+                                    .type            = CODEC_TYPE_VIDEO, },
+                                  { .name = NULL}},
+};
+
+
Index: doc/vfilters.texi
===================================================================
--- doc/vfilters.texi   (revision 4315)
+++ doc/vfilters.texi   (working copy)
@@ -69,6 +69,22 @@
 
 These are the currently available video filters:
 
+...@section applyfn
+
+Apply a function to each channel
+
+...@example
+./ffmpeg -i in.avi -vfilters "applyfn= Y=Y : U=128 : V=128" out.avi
+...@end example
+
+Convert the video to BW.
+
+...@example
+./ffmpeg -i in.avi -vfilters "applyfn= Y_exp=255-Y: U_exp=255-U: V_exp=255-V" out.avi
+...@end example
+
+Negate the video
+
 @section crop
 
 @example
_______________________________________________
FFmpeg-soc mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-soc

Reply via email to