[FFmpeg-devel] [Patch] Scale filter should use multiples of 2
Stefano Sabatini
stefano.sabatini-lala
Thu Jul 22 18:42:55 CEST 2010
On date Thursday 2010-07-22 11:33:10 -0400, Daniel G. Taylor encoded:
> On 07/21/2010 08:04 PM, Stefano Sabatini wrote:
>> Ehm, after further inspection of the code I discovered that the graph
>> parser *already* supports escaping (through the av_get_token()
>> function).
>>
>> So for the particular case above:
>> "scale=W:round(H\, 16)"
>>
>> or even:
>> 'scale=W:round(H, 16)'
>
> Okay, awesome. I've confirmed that works, along with stuff like:
>
> ffmpeg -i in.mp4 -vf "scale=PI*100:round(PI*100/A\, 16)" out.mp4
>
> I've also fixed all the comments from the other mail, and as you can see
> above added PI and E. Updated patch is attached. There are now two
> issues I'm a little stuck with and would like your thoughts on:
>
> * With zero arguments it crashes. It appears 'flags=0x...' is
> magically appended to args and I have no idea where and what
> is going on. Can one of you C string parsing gurus take a look
> at the best way to parse the args here?
This is automatically added by ffmpeg or the graphparser, that's an
hack we use to propagate the scaling flags to use.
I suppose we may fix that *requiring* a syntax of the kind:
W:H:FLAGS
rather than try to intercept the flags= string.
Anyway I'd rather expect the filter to issue a configuration error,
further debugging information is required.
> * The special case of -1 can't work within the expression parser, so
> if you want to round e.g. scale=320:-1 you now would have to
> do "scale=320:round(320/H\, 16)". Any way to fix this or is
> it okay this way?
We may keep the interpretation of -1 as a special value, but also
using W2/H1 looks fine to me (and imho less surprising for a new
user).
> Take care,
> --
> Daniel G. Taylor
> http://programmer-art.org/
> Index: libavfilter/vf_scale.c
> ===================================================================
> --- libavfilter/vf_scale.c (revision 24077)
> +++ libavfilter/vf_scale.c (working copy)
> @@ -1,5 +1,6 @@
> /*
> * copyright (c) 2007 Bobby Bingham
> + * copyright (c) 2010 Daniel G. Taylor <dan at programmer-art.org>
> *
> * This file is part of FFmpeg.
> *
> @@ -24,44 +25,91 @@
> */
>
> #include "avfilter.h"
> +#include "libavutil/eval.h"
> #include "libavutil/pixdesc.h"
> #include "libswscale/swscale.h"
> +static const char *var_names[]={
> + "PI",
> + "E",
> + "W",
> + "H",
> + "A",
> + NULL
> +};
> +
> +enum var_name {
> + PI,
> + E,
> + W,
> + H,
> + A,
> + VARS_NB
> +};
alphabetical order, avoid potential bugs.
> +
> +static inline double round_clip(void *ctx, double arg1, double arg2)
> +{
> + int orig = (int)arg1;
> + int clip = (int)arg2;
> +
> + return orig -= (orig % clip < clip / 2) ? orig % clip : -(clip - (orig % clip));
> +}
> +
> +static const char *func2_names[]={
nit: _=_{
> + "round",
> + NULL
> +};
> +
>
> +static double (* const *funcs2[])(void *, double, double)={
> + (void *)round_clip,
> + NULL
> +};
> +
> typedef struct {
> struct SwsContext *sws; ///< software scaler context
>
> - /**
> - * New dimensions. Special values are:
> - * 0 = original width/height
> - * -1 = keep original aspect
> - */
> - int w, h;
> - unsigned int flags; ///sws flags
> + int w, h; ///< new dimensions
> + unsigned int flags; ///< sws flags
>
> int hsub, vsub; ///< chroma subsampling
> int slice_y; ///< top of current output slice
> int input_is_pal; ///< set to 1 if the input format is paletted
> +
> + AVExpr *w_expr; ///< width expression
> + AVExpr *h_expr; ///< height expression
> + double var_values[VARS_NB+1]; ///< expression parsing constants
> } ScaleContext;
>
> static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
> {
> ScaleContext *scale = ctx->priv;
> const char *p;
> + char width[255] = "W", height[255] = "H";
> + int ret;
> + char *save_ptr = NULL;
>
> scale->flags = SWS_BILINEAR;
> if (args){
> - sscanf(args, "%d:%d", &scale->w, &scale->h);
> + sscanf(args, "%255[^:]:%255[^:]", &width, &height);
> p= strstr(args,"flags=");
> if(p) scale->flags= strtoul(p+6, NULL, 0);
> }
this fails if you have the string: flags=.. appended to args.
I believe the best solution would be to change the scale syntax to
W:H:FLAGS, thoughts?
> -
> - /* sanity check params */
> - if (scale->w < -1 || scale->h < -1) {
> - av_log(ctx, AV_LOG_ERROR, "Size values less than -1 are not acceptable.\n");
> - return -1;
> +
> + ret = av_parse_expr(&scale->w_expr, width, var_names, NULL, NULL,
> + func2_names, funcs2, 0, ctx);
> + if (ret < 0) {
> + av_log(ctx, AV_LOG_ERROR,
> + "Error while parsing width expression '%s'\n", width);
> + return ret;
> }
> - if (scale->w == -1 && scale->h == -1)
> - scale->w = scale->h = 0;
> +
> + ret = av_parse_expr(&scale->h_expr, height, var_names, NULL, NULL,
> + func2_names, funcs2, 0, ctx);
> + if (ret < 0) {
> + av_log(ctx, AV_LOG_ERROR,
> + "Error while parsing height expression '%s'\n", height);
> + return ret;
> + }
code duplication, look at how it's done in the libavfilter soc overlay
filter to avoid it.
>
> return 0;
> }
> @@ -109,11 +157,19 @@
> AVFilterLink *inlink = outlink->src->inputs[0];
> ScaleContext *scale = ctx->priv;
> int64_t w, h;
> +
> + scale->var_values[PI] = M_PI;
> + scale->var_values[E] = M_E;
> + scale->var_values[W] = inlink->w;
> + scale->var_values[H] = inlink->h;
> + scale->var_values[A] = (float) inlink->w / inlink->h;
vertical align.
> +
> + scale->w = av_eval_expr(scale->w_expr, scale->var_values, scale);
> + scale->h = av_eval_expr(scale->h_expr, scale->var_values, scale);
BTW in order to avoid to parse and eval as two separate operations as
you need to evaluate the expression just once, you may just use here
av_parse_and_eval_expr(), that may simplify the code a bit.
>
> - if (!(w = scale->w))
> - w = inlink->w;
> - if (!(h = scale->h))
> - h = inlink->h;
> + w = scale->w;
> + h = scale->h;
> +
> if (w == -1)
> w = av_rescale(h, inlink->w, inlink->h);
> if (h == -1)
Regards.
--
FFmpeg = Furious and Fundamental Multipurpose Programmable Elaborated Gigant
More information about the ffmpeg-devel
mailing list