Hi,
----- "Stefano Sabatini" <[email protected]> wrote:
> I believe pow *is* supported out of the box by the eval code.
It is not enabled in the parse_primary(Parser *p) function.
> Docs and example go to doc/vfilters.texi.
Removed them.
> enum VarName {
> ...
> VARS_NB
> };
>
> is better.
Done.
>
> And a PTS var may be useful too.
>
Working on that.
> > +static const char *applyfn_symbols[POV_NULL+1]={
> ^^
> Why +1?
I copied the code from vf_setpts, didn't gave it second thought.
> > + ApplyfnContext *applyfn = ctx->priv;
> > + char Y_expr[256], U_expr[256], V_expr[256], A_expr[256];
> > + const char *error;
>
> Weird indent.
>
Fixed.
> > + sscanf(args, "%255[^:]:%255[^:]:%255[^:]:%255[^:]", Y_expr, U_expr,
> > V_expr, A_expr)
>
> I believe here it would be nice to use av_set_options_string, check
> vf_pad.c in the archive for an usage example.
Done.
> > + 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);
> This can be factorized (check again vf_pad.c to see how), maybe even a
> macro may be used.
I created a macro for it, I'm not sure if it is okay according to
FFmpeg coding standards.
> > +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;
>
> Ouch, this is wrong, as draw_slice() is called for every slice(), and
> you don't know how many slices there are. This update should be done
> in start_frame() / end_frame() (same for W and H, since they're not
> supposed to change between a slice and another one).
>
Moved the code to start_frame.
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?
Thanks for the feedback!
Zeger Knops
Index: vf_applyfn.c
===================================================================
--- vf_applyfn.c (revision 0)
+++ vf_applyfn.c (revision 0)
@@ -0,0 +1,268 @@
+/*
+ * 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,
+ 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
+ "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;
+ AVEvalExpr *Y_evalexpr, *U_evalexpr, *V_evalexpr, *A_evalexpr;
+ int hsub, vsub;
+ 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},
+{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");
+
+ if (args && av_set_options_string(applyfn, args, "=", ":") < 0)
+ return -1;
+
+ FF_PARSE( Y );
+ FF_PARSE( U );
+ FF_PARSE( V );
+ FF_PARSE( A );
+
+ 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);
+}
+
+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)
+{
+ AVFilterLink *out = NULL;
+ ApplyfnContext *applyfn = link->dst->priv;
+
+ applyfn->var_values[N] += 1.0;
+
+ applyfn->var_values[W] = link->w;
+ applyfn->var_values[H] = link->h;
+
+ if(link->dst->output_count)
+ out = link->dst->outputs[0];
+
+ if(out) {
+ out->outpic = avfilter_get_video_buffer(out, AV_PERM_WRITE);
+ out->outpic->pts = picref->pts;
+ avfilter_start_frame(out, avfilter_ref_pic(out->outpic, ~0));
+ }
+}
+
+static void end_frame(AVFilterLink *link)
+{
+ avfilter_end_frame(link->dst->outputs[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;
+
+ 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];
+
+ if ( out->data[3] )
+ 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;
+
+ 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,
+ .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}},
+};
+
+
_______________________________________________
FFmpeg-soc mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-soc