On 01/02/17 00:46, Aman Gupta wrote: > From: Aman Gupta <a...@tmm1.net> > > Implements support for height/width expressions in vf_scale_vaapi, > by refactoring common code into a new libavfilter/scale.c
Nice! Patch as a whole LGTM, some minor nits below. > --- > libavfilter/Makefile | 8 +-- > libavfilter/scale.c | 143 > +++++++++++++++++++++++++++++++++++++++++++ > libavfilter/scale.h | 31 ++++++++++ > libavfilter/vf_scale.c | 109 +++------------------------------ > libavfilter/vf_scale_npp.c | 87 +++----------------------- > libavfilter/vf_scale_vaapi.c | 18 +++++- > 6 files changed, 208 insertions(+), 188 deletions(-) > create mode 100644 libavfilter/scale.c > create mode 100644 libavfilter/scale.h > > diff --git a/libavfilter/Makefile b/libavfilter/Makefile > index 68a94be..3231f08 100644 > --- a/libavfilter/Makefile > +++ b/libavfilter/Makefile > @@ -257,10 +257,10 @@ OBJS-$(CONFIG_REPEATFIELDS_FILTER) += > vf_repeatfields.o > OBJS-$(CONFIG_REVERSE_FILTER) += f_reverse.o > OBJS-$(CONFIG_ROTATE_FILTER) += vf_rotate.o > OBJS-$(CONFIG_SAB_FILTER) += vf_sab.o > -OBJS-$(CONFIG_SCALE_FILTER) += vf_scale.o > -OBJS-$(CONFIG_SCALE_NPP_FILTER) += vf_scale_npp.o > -OBJS-$(CONFIG_SCALE_VAAPI_FILTER) += vf_scale_vaapi.o > -OBJS-$(CONFIG_SCALE2REF_FILTER) += vf_scale.o > +OBJS-$(CONFIG_SCALE_FILTER) += vf_scale.o scale.o > +OBJS-$(CONFIG_SCALE_NPP_FILTER) += vf_scale_npp.o scale.o > +OBJS-$(CONFIG_SCALE_VAAPI_FILTER) += vf_scale_vaapi.o scale.o > +OBJS-$(CONFIG_SCALE2REF_FILTER) += vf_scale.o scale.o > OBJS-$(CONFIG_SELECT_FILTER) += f_select.o > OBJS-$(CONFIG_SELECTIVECOLOR_FILTER) += vf_selectivecolor.o > OBJS-$(CONFIG_SENDCMD_FILTER) += f_sendcmd.o > diff --git a/libavfilter/scale.c b/libavfilter/scale.c > new file mode 100644 > index 0000000..b0f4be2 > --- /dev/null > +++ b/libavfilter/scale.c > @@ -0,0 +1,143 @@ > +/* > + * 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 "scale.h" > + > +static const char *const var_names[] = { > + "PI", > + "PHI", > + "E", > + "in_w", "iw", > + "in_h", "ih", > + "out_w", "ow", > + "out_h", "oh", > + "a", > + "sar", > + "dar", > + "hsub", > + "vsub", > + "ohsub", > + "ovsub", > + NULL > +}; > + > +enum var_name { > + VAR_PI, > + VAR_PHI, > + VAR_E, > + VAR_IN_W, VAR_IW, > + VAR_IN_H, VAR_IH, > + VAR_OUT_W, VAR_OW, > + VAR_OUT_H, VAR_OH, > + VAR_A, > + VAR_SAR, > + VAR_DAR, > + VAR_HSUB, > + VAR_VSUB, > + VAR_OHSUB, > + VAR_OVSUB, > + VARS_NB > +}; > + > +int ff_scale_eval_dimensions(void *ctx, > + const char *w_expr, const char *h_expr, > + AVFilterLink *inlink, AVFilterLink *outlink, > + int *ret_w, int *ret_h) > +{ > + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); > + const AVPixFmtDescriptor *out_desc = > av_pix_fmt_desc_get(outlink->format); > + const char *expr; > + int w, h; > + int factor_w, factor_h; > + int eval_w, eval_h; > + int ret; > + double var_values[VARS_NB], res; > + > + var_values[VAR_IN_W] = var_values[VAR_IW] = inlink->w; > + var_values[VAR_IN_H] = var_values[VAR_IH] = inlink->h; > + var_values[VAR_OUT_W] = var_values[VAR_OW] = NAN; > + var_values[VAR_OUT_H] = var_values[VAR_OH] = NAN; > + var_values[VAR_A] = (double) inlink->w / inlink->h; > + var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ? > + (double) inlink->sample_aspect_ratio.num / > inlink->sample_aspect_ratio.den : 1; > + var_values[VAR_DAR] = var_values[VAR_A] * var_values[VAR_SAR]; > + var_values[VAR_HSUB] = 1 << desc->log2_chroma_w; > + var_values[VAR_VSUB] = 1 << desc->log2_chroma_h; > + var_values[VAR_OHSUB] = 1 << out_desc->log2_chroma_w; > + var_values[VAR_OVSUB] = 1 << out_desc->log2_chroma_h; > + > + /* evaluate width and height */ > + av_expr_parse_and_eval(&res, (expr = w_expr), > + var_names, var_values, > + NULL, NULL, NULL, NULL, NULL, 0, ctx); > + eval_w = var_values[VAR_OUT_W] = var_values[VAR_OW] = res; > + > + if ((ret = av_expr_parse_and_eval(&res, (expr = h_expr), > + var_names, var_values, > + NULL, NULL, NULL, NULL, NULL, 0, ctx)) > < 0) > + goto fail; > + eval_h = var_values[VAR_OUT_H] = var_values[VAR_OH] = res; > + /* evaluate again the width, as it may depend on the output height */ > + if ((ret = av_expr_parse_and_eval(&res, (expr = w_expr), > + var_names, var_values, > + NULL, NULL, NULL, NULL, NULL, 0, ctx)) > < 0) > + goto fail; > + eval_w = res; > + > + w = eval_w; > + h = eval_h; > + > + /* Check if it is requested that the result has to be divisible by a some > + * factor (w or h = -n with n being the factor). */ > + factor_w = 1; > + factor_h = 1; > + if (w < -1) { > + factor_w = -w; > + } > + if (h < -1) { > + factor_h = -h; > + } > + > + if (w < 0 && h < 0) > + eval_w = eval_h = 0; > + > + if (!(w = eval_w)) > + w = inlink->w; > + if (!(h = eval_h)) > + h = inlink->h; > + > + /* Make sure that the result is divisible by the factor we determined > + * earlier. If no factor was set, it is nothing will happen as the > default > + * factor is 1 */ > + if (w < 0) > + w = av_rescale(h, inlink->w, inlink->h * factor_w) * factor_w; > + if (h < 0) > + h = av_rescale(w, inlink->h, inlink->w * factor_h) * factor_h; > + > + *ret_w = w; > + *ret_h = h; > + > + return 0; > + > +fail: > + av_log(NULL, AV_LOG_ERROR, > + "Error when evaluating the expression '%s'.\n" > + "Maybe the expression for out_w:'%s' or for out_h:'%s' is > self-referencing.\n", > + expr, w_expr, h_expr); > + return ret; > +} > diff --git a/libavfilter/scale.h b/libavfilter/scale.h > new file mode 100644 > index 0000000..c95515d > --- /dev/null > +++ b/libavfilter/scale.h > @@ -0,0 +1,31 @@ > +/* > + * 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 > + */ > + > +#ifndef AVFILTER_SCALE_H > +#define AVFILTER_SCALE_H > + > +#include <stdint.h> > +#include "avfilter.h" > +#include "libavutil/eval.h" > +#include "libavutil/pixdesc.h" You don't need all of these includes in the header; they should go in scale.c. > + > +int ff_scale_eval_dimensions(void *ctx, > + const char *w_expr, const char *h_expr, > + AVFilterLink *inlink, AVFilterLink *outlink, > + int *ret_w, int *ret_h); > +#endif > diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c > index 22bee96..8645da7 100644 > --- a/libavfilter/vf_scale.c > +++ b/libavfilter/vf_scale.c > @@ -29,9 +29,9 @@ > #include "avfilter.h" > #include "formats.h" > #include "internal.h" > +#include "scale.h" > #include "video.h" > #include "libavutil/avstring.h" > -#include "libavutil/eval.h" > #include "libavutil/internal.h" > #include "libavutil/mathematics.h" > #include "libavutil/opt.h" > @@ -41,43 +41,12 @@ > #include "libavutil/avassert.h" > #include "libswscale/swscale.h" > > -static const char *const var_names[] = { > - "in_w", "iw", > - "in_h", "ih", > - "out_w", "ow", > - "out_h", "oh", > - "a", > - "sar", > - "dar", > - "hsub", > - "vsub", > - "ohsub", > - "ovsub", > - NULL > -}; > - > -enum var_name { > - VAR_IN_W, VAR_IW, > - VAR_IN_H, VAR_IH, > - VAR_OUT_W, VAR_OW, > - VAR_OUT_H, VAR_OH, > - VAR_A, > - VAR_SAR, > - VAR_DAR, > - VAR_HSUB, > - VAR_VSUB, > - VAR_OHSUB, > - VAR_OVSUB, > - VARS_NB > -}; > - > enum EvalMode { > EVAL_MODE_INIT, > EVAL_MODE_FRAME, > EVAL_MODE_NB > }; > > - > typedef struct ScaleContext { > const AVClass *class; > struct SwsContext *sws; ///< software scaler context > @@ -256,74 +225,16 @@ static int config_props(AVFilterLink *outlink) > outlink->src->inputs[1] : > outlink->src->inputs[0]; > enum AVPixelFormat outfmt = outlink->format; > - ScaleContext *scale = ctx->priv; > const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); > - const AVPixFmtDescriptor *out_desc = > av_pix_fmt_desc_get(outlink->format); > - int64_t w, h; > - double var_values[VARS_NB], res; > - char *expr; > + ScaleContext *scale = ctx->priv; > + int w, h; > int ret; > - int factor_w, factor_h; > - > - var_values[VAR_IN_W] = var_values[VAR_IW] = inlink->w; > - var_values[VAR_IN_H] = var_values[VAR_IH] = inlink->h; > - var_values[VAR_OUT_W] = var_values[VAR_OW] = NAN; > - var_values[VAR_OUT_H] = var_values[VAR_OH] = NAN; > - var_values[VAR_A] = (double) inlink->w / inlink->h; > - var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ? > - (double) inlink->sample_aspect_ratio.num / > inlink->sample_aspect_ratio.den : 1; > - var_values[VAR_DAR] = var_values[VAR_A] * var_values[VAR_SAR]; > - var_values[VAR_HSUB] = 1 << desc->log2_chroma_w; > - var_values[VAR_VSUB] = 1 << desc->log2_chroma_h; > - var_values[VAR_OHSUB] = 1 << out_desc->log2_chroma_w; > - var_values[VAR_OVSUB] = 1 << out_desc->log2_chroma_h; > - > - /* evaluate width and height */ > - av_expr_parse_and_eval(&res, (expr = scale->w_expr), > - var_names, var_values, > - NULL, NULL, NULL, NULL, NULL, 0, ctx); > - scale->w = var_values[VAR_OUT_W] = var_values[VAR_OW] = res; > - if ((ret = av_expr_parse_and_eval(&res, (expr = scale->h_expr), > - var_names, var_values, > - NULL, NULL, NULL, NULL, NULL, 0, ctx)) > < 0) > - goto fail; > - scale->h = var_values[VAR_OUT_H] = var_values[VAR_OH] = res; > - /* evaluate again the width, as it may depend on the output height */ > - if ((ret = av_expr_parse_and_eval(&res, (expr = scale->w_expr), > - var_names, var_values, > - NULL, NULL, NULL, NULL, NULL, 0, ctx)) > < 0) > - goto fail; > - scale->w = res; > - > - w = scale->w; > - h = scale->h; > - > - /* Check if it is requested that the result has to be divisible by a some > - * factor (w or h = -n with n being the factor). */ > - factor_w = 1; > - factor_h = 1; > - if (w < -1) { > - factor_w = -w; > - } > - if (h < -1) { > - factor_h = -h; > - } > - > - if (w < 0 && h < 0) > - scale->w = scale->h = 0; > > - if (!(w = scale->w)) > - w = inlink->w; > - if (!(h = scale->h)) > - h = inlink->h; > - > - /* Make sure that the result is divisible by the factor we determined > - * earlier. If no factor was set, it is nothing will happen as the > default > - * factor is 1 */ > - if (w < 0) > - w = av_rescale(h, inlink->w, inlink->h * factor_w) * factor_w; > - if (h < 0) > - h = av_rescale(w, inlink->h, inlink->w * factor_h) * factor_h; > + if ((ret = ff_scale_eval_dimensions(ctx, > + scale->w_expr, scale->h_expr, > + inlink, outlink, > + &w, &h)) < 0) > + goto fail; > > /* Note that force_original_aspect_ratio may overwrite the previous set > * dimensions so that it is not divisible by the set factors anymore. */ > @@ -439,10 +350,6 @@ static int config_props(AVFilterLink *outlink) > return 0; > > fail: > - av_log(NULL, AV_LOG_ERROR, > - "Error when evaluating the expression '%s'.\n" > - "Maybe the expression for out_w:'%s' or for out_h:'%s' is > self-referencing.\n", > - expr, scale->w_expr, scale->h_expr); > return ret; > } > > diff --git a/libavfilter/vf_scale_npp.c b/libavfilter/vf_scale_npp.c > index 1abfdd1..84d88eb 100644 > --- a/libavfilter/vf_scale_npp.c > +++ b/libavfilter/vf_scale_npp.c > @@ -27,7 +27,6 @@ > > #include "libavutil/avstring.h" > #include "libavutil/common.h" > -#include "libavutil/eval.h" > #include "libavutil/hwcontext.h" > #include "libavutil/hwcontext_cuda_internal.h" > #include "libavutil/internal.h" > @@ -38,6 +37,7 @@ > #include "avfilter.h" > #include "formats.h" > #include "internal.h" > +#include "scale.h" > #include "video.h" > > static const enum AVPixelFormat supported_formats[] = { > @@ -50,32 +50,6 @@ static const enum AVPixelFormat deinterleaved_formats[][2] > = { > { AV_PIX_FMT_NV12, AV_PIX_FMT_YUV420P }, > }; > > -static const char *const var_names[] = { > - "PI", > - "PHI", > - "E", > - "in_w", "iw", > - "in_h", "ih", > - "out_w", "ow", > - "out_h", "oh", > - "a", "dar", > - "sar", > - NULL > -}; > - > -enum var_name { > - VAR_PI, > - VAR_PHI, > - VAR_E, > - VAR_IN_W, VAR_IW, > - VAR_IN_H, VAR_IH, > - VAR_OUT_W, VAR_OW, > - VAR_OUT_H, VAR_OH, > - VAR_A, VAR_DAR, > - VAR_SAR, > - VARS_NB > -}; > - > enum ScaleStage { > STAGE_DEINTERLEAVE, > STAGE_RESIZE, > @@ -359,60 +333,15 @@ static int nppscale_config_props(AVFilterLink *outlink) > { > AVFilterContext *ctx = outlink->src; > AVFilterLink *inlink = outlink->src->inputs[0]; > - NPPScaleContext *s = ctx->priv; > - int64_t w, h; > - double var_values[VARS_NB], res; > - char *expr; > + NPPScaleContext *s = ctx->priv; > + int w, h; > int ret; > > - var_values[VAR_PI] = M_PI; > - var_values[VAR_PHI] = M_PHI; > - var_values[VAR_E] = M_E; > - var_values[VAR_IN_W] = var_values[VAR_IW] = inlink->w; > - var_values[VAR_IN_H] = var_values[VAR_IH] = inlink->h; > - var_values[VAR_OUT_W] = var_values[VAR_OW] = NAN; > - var_values[VAR_OUT_H] = var_values[VAR_OH] = NAN; > - var_values[VAR_A] = (double) inlink->w / inlink->h; > - var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ? > - (double) inlink->sample_aspect_ratio.num / > inlink->sample_aspect_ratio.den : 1; > - var_values[VAR_DAR] = var_values[VAR_A] * var_values[VAR_SAR]; > - > - /* evaluate width and height */ > - av_expr_parse_and_eval(&res, (expr = s->w_expr), > - var_names, var_values, > - NULL, NULL, NULL, NULL, NULL, 0, ctx); > - s->w = var_values[VAR_OUT_W] = var_values[VAR_OW] = res; > - if ((ret = av_expr_parse_and_eval(&res, (expr = s->h_expr), > - var_names, var_values, > - NULL, NULL, NULL, NULL, NULL, 0, ctx)) > < 0) > + if ((ret = ff_scale_eval_dimensions(s, > + s->w_expr, s->h_expr, > + inlink, outlink, > + &w, &h)) < 0) > goto fail; > - s->h = var_values[VAR_OUT_H] = var_values[VAR_OH] = res; > - /* evaluate again the width, as it may depend on the output height */ > - if ((ret = av_expr_parse_and_eval(&res, (expr = s->w_expr), > - var_names, var_values, > - NULL, NULL, NULL, NULL, NULL, 0, ctx)) > < 0) > - goto fail; > - s->w = res; > - > - w = s->w; > - h = s->h; > - > - /* sanity check params */ > - if (w < -1 || h < -1) { > - av_log(ctx, AV_LOG_ERROR, "Size values less than -1 are not > acceptable.\n"); > - return AVERROR(EINVAL); > - } > - if (w == -1 && h == -1) > - s->w = s->h = 0; > - > - if (!(w = s->w)) > - w = inlink->w; > - if (!(h = s->h)) > - h = inlink->h; > - if (w == -1) > - w = av_rescale(h, inlink->w, inlink->h); > - if (h == -1) > - h = av_rescale(w, inlink->h, inlink->w); > > if (w > INT_MAX || h > INT_MAX || > (h * inlink->w) > INT_MAX || > (w * inlink->h) > INT_MAX) > av_log(ctx, AV_LOG_ERROR, "Rescaled value for width or height is too > big.\n"); This test doesn't work any more - all of w, h and the corresponding AVFilterLink fields are int, so the test will just invoke undefined behaviour on signed overflow rather than testing anything. Add some casts, I think? (I assume this is trying to enforce some constraint of the npp API.) > @@ -439,8 +368,6 @@ static int nppscale_config_props(AVFilterLink *outlink) > return 0; > > fail: > - av_log(NULL, AV_LOG_ERROR, > - "Error when evaluating the expression '%s'\n", expr); > return ret; > } > > diff --git a/libavfilter/vf_scale_vaapi.c b/libavfilter/vf_scale_vaapi.c > index d1cb246..1abb42e 100644 > --- a/libavfilter/vf_scale_vaapi.c > +++ b/libavfilter/vf_scale_vaapi.c > @@ -31,6 +31,7 @@ > #include "avfilter.h" > #include "formats.h" > #include "internal.h" > +#include "scale.h" > > typedef struct ScaleVAAPIContext { > const AVClass *class; > @@ -50,9 +51,13 @@ typedef struct ScaleVAAPIContext { > > char *output_format_string; > enum AVPixelFormat output_format; > + > + char *w_expr; ///< width expression string > + char *h_expr; ///< height expression string > + > + /* computed width/height */ Keep the comment style consistent? (I'd go for // and no doxygen markers, but anything consistent is fine.) > int output_width; > int output_height; > - > } ScaleVAAPIContext; > > > @@ -110,6 +115,7 @@ static int scale_vaapi_config_input(AVFilterLink *inlink) > > static int scale_vaapi_config_output(AVFilterLink *outlink) > { > + AVFilterLink *inlink = outlink->src->inputs[0]; > AVFilterContext *avctx = outlink->src; > ScaleVAAPIContext *ctx = avctx->priv; > AVVAAPIHWConfig *hwconfig = NULL; > @@ -162,6 +168,12 @@ static int scale_vaapi_config_output(AVFilterLink > *outlink) > } > } > > + if ((err = ff_scale_eval_dimensions(ctx, > + ctx->w_expr, ctx->h_expr, > + inlink, outlink, > + &ctx->output_width, > &ctx->output_height)) < 0) > + goto fail; > + > if (ctx->output_width < constraints->min_width || > ctx->output_height < constraints->min_height || > ctx->output_width > constraints->max_width || > @@ -414,9 +426,9 @@ static av_cold void scale_vaapi_uninit(AVFilterContext > *avctx) > #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM) > static const AVOption scale_vaapi_options[] = { > { "w", "Output video width", > - OFFSET(output_width), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, > .flags = FLAGS }, > + OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = "iw"}, .flags = FLAGS }, > { "h", "Output video height", > - OFFSET(output_height), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, > .flags = FLAGS }, > + OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = "ih"}, .flags = FLAGS }, > { "format", "Output video format (software format of hardware frames)", > OFFSET(output_format_string), AV_OPT_TYPE_STRING, .flags = FLAGS }, > { NULL }, > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel