From patchwork Thu Nov 14 17:42:23 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gyan Doshi X-Patchwork-Id: 16272 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 5CE42448D99 for ; Thu, 14 Nov 2019 19:42:38 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 36ACE68A471; Thu, 14 Nov 2019 19:42:38 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mout-p-202.mailbox.org (mout-p-202.mailbox.org [80.241.56.172]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id E3C20689C64 for ; Thu, 14 Nov 2019 19:42:31 +0200 (EET) Received: from smtp2.mailbox.org (smtp2.mailbox.org [80.241.60.241]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by mout-p-202.mailbox.org (Postfix) with ESMTPS id 47DTMV6tVlzQlB0 for ; Thu, 14 Nov 2019 18:42:30 +0100 (CET) X-Virus-Scanned: amavisd-new at heinlein-support.de Received: from smtp2.mailbox.org ([80.241.60.241]) by spamfilter02.heinlein-hosting.de (spamfilter02.heinlein-hosting.de [80.241.56.116]) (amavisd-new, port 10030) with ESMTP id IlZtRDs5yweA for ; Thu, 14 Nov 2019 18:42:26 +0100 (CET) To: ffmpeg-devel@ffmpeg.org References: <9341df3e-b89a-b689-1b4f-e5b4155fe3c8@gyani.pro> <20191113194213.GY11865@michaelspb> From: Gyan Message-ID: <6ef1020f-fe47-4b63-1d8a-ebe7d199e8cc@gyani.pro> Date: Thu, 14 Nov 2019 23:12:23 +0530 MIME-Version: 1.0 In-Reply-To: <20191113194213.GY11865@michaelspb> Content-Language: en-US Subject: Re: [FFmpeg-devel] [PATCH] avfilter/scale: allow dynamic output via expressions X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" On 14-11-2019 01:12 am, Michael Niedermayer wrote: > Moving and changing code at the same time makes it hard to see th difference. > Idealy all code moves should be seperate from changes to the code. > > also more generally, spliting this patch up would simpify review Split into two. First patch mostly moves code and keeps existing functionality. 2nd patch introduces new features and requires the new eval function. Thanks, Gyan From 359f538703865c8ebeda16b5d1846d2cf1cf9c4d Mon Sep 17 00:00:00 2001 From: Gyan Doshi Date: Thu, 14 Nov 2019 21:08:32 +0530 Subject: [PATCH v2 1/2] avfilter/scale: shift ff_scale_eval_dimensions inline This is a perfunctory change in preparation of adding direct animation support to scale and scale2ref filters --- libavfilter/Makefile | 4 +- libavfilter/scale.c | 72 +--------------- libavfilter/vf_scale.c | 192 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 196 insertions(+), 72 deletions(-) diff --git a/libavfilter/Makefile b/libavfilter/Makefile index fce930360d..f1f6994574 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -358,12 +358,12 @@ OBJS-$(CONFIG_ROBERTS_OPENCL_FILTER) += vf_convolution_opencl.o opencl.o opencl/convolution.o OBJS-$(CONFIG_ROTATE_FILTER) += vf_rotate.o OBJS-$(CONFIG_SAB_FILTER) += vf_sab.o -OBJS-$(CONFIG_SCALE_FILTER) += vf_scale.o scale.o +OBJS-$(CONFIG_SCALE_FILTER) += vf_scale.o OBJS-$(CONFIG_SCALE_CUDA_FILTER) += vf_scale_cuda.o vf_scale_cuda.ptx.o OBJS-$(CONFIG_SCALE_NPP_FILTER) += vf_scale_npp.o scale.o OBJS-$(CONFIG_SCALE_QSV_FILTER) += vf_scale_qsv.o OBJS-$(CONFIG_SCALE_VAAPI_FILTER) += vf_scale_vaapi.o scale.o vaapi_vpp.o -OBJS-$(CONFIG_SCALE2REF_FILTER) += vf_scale.o scale.o +OBJS-$(CONFIG_SCALE2REF_FILTER) += vf_scale.o OBJS-$(CONFIG_SCROLL_FILTER) += vf_scroll.o OBJS-$(CONFIG_SELECT_FILTER) += f_select.o OBJS-$(CONFIG_SELECTIVECOLOR_FILTER) += vf_selectivecolor.o diff --git a/libavfilter/scale.c b/libavfilter/scale.c index eaee95fac6..668aa04622 100644 --- a/libavfilter/scale.c +++ b/libavfilter/scale.c @@ -60,49 +60,6 @@ enum var_name { VARS_NB }; -/** - * This must be kept in sync with var_names so that it is always a - * complete list of var_names with the scale2ref specific names - * appended. scale2ref values must appear in the order they appear - * in the var_name_scale2ref enum but also be below all of the - * non-scale2ref specific values. - */ -static const char *const var_names_scale2ref[] = { - "PI", - "PHI", - "E", - "in_w", "iw", - "in_h", "ih", - "out_w", "ow", - "out_h", "oh", - "a", - "sar", - "dar", - "hsub", - "vsub", - "ohsub", - "ovsub", - "main_w", - "main_h", - "main_a", - "main_sar", - "main_dar", "mdar", - "main_hsub", - "main_vsub", - NULL -}; - -enum var_name_scale2ref { - VAR_S2R_MAIN_W, - VAR_S2R_MAIN_H, - VAR_S2R_MAIN_A, - VAR_S2R_MAIN_SAR, - VAR_S2R_MAIN_DAR, VAR_S2R_MDAR, - VAR_S2R_MAIN_HSUB, - VAR_S2R_MAIN_VSUB, - VARS_S2R_NB -}; - int ff_scale_eval_dimensions(void *log_ctx, const char *w_expr, const char *h_expr, AVFilterLink *inlink, AVFilterLink *outlink, @@ -115,16 +72,7 @@ int ff_scale_eval_dimensions(void *log_ctx, int factor_w, factor_h; int eval_w, eval_h; int ret; - const char scale2ref = outlink->src->nb_inputs == 2 && outlink->src->inputs[1] == inlink; - double var_values[VARS_NB + VARS_S2R_NB], res; - const AVPixFmtDescriptor *main_desc; - const AVFilterLink *main_link; - const char *const *names = scale2ref ? var_names_scale2ref : var_names; - - if (scale2ref) { - main_link = outlink->src->inputs[0]; - main_desc = av_pix_fmt_desc_get(main_link->format); - } + double var_values[VARS_NB], res; var_values[VAR_PI] = M_PI; var_values[VAR_PHI] = M_PHI; @@ -142,32 +90,20 @@ int ff_scale_eval_dimensions(void *log_ctx, var_values[VAR_OHSUB] = 1 << out_desc->log2_chroma_w; var_values[VAR_OVSUB] = 1 << out_desc->log2_chroma_h; - if (scale2ref) { - var_values[VARS_NB + VAR_S2R_MAIN_W] = main_link->w; - var_values[VARS_NB + VAR_S2R_MAIN_H] = main_link->h; - var_values[VARS_NB + VAR_S2R_MAIN_A] = (double) main_link->w / main_link->h; - var_values[VARS_NB + VAR_S2R_MAIN_SAR] = main_link->sample_aspect_ratio.num ? - (double) main_link->sample_aspect_ratio.num / main_link->sample_aspect_ratio.den : 1; - var_values[VARS_NB + VAR_S2R_MAIN_DAR] = var_values[VARS_NB + VAR_S2R_MDAR] = - var_values[VARS_NB + VAR_S2R_MAIN_A] * var_values[VARS_NB + VAR_S2R_MAIN_SAR]; - var_values[VARS_NB + VAR_S2R_MAIN_HSUB] = 1 << main_desc->log2_chroma_w; - var_values[VARS_NB + VAR_S2R_MAIN_VSUB] = 1 << main_desc->log2_chroma_h; - } - /* evaluate width and height */ av_expr_parse_and_eval(&res, (expr = w_expr), - names, var_values, + var_names, var_values, NULL, NULL, NULL, NULL, NULL, 0, log_ctx); eval_w = var_values[VAR_OUT_W] = var_values[VAR_OW] = (int) res == 0 ? inlink->w : (int) res; if ((ret = av_expr_parse_and_eval(&res, (expr = h_expr), - names, var_values, + var_names, var_values, NULL, NULL, NULL, NULL, NULL, 0, log_ctx)) < 0) goto fail; eval_h = var_values[VAR_OUT_H] = var_values[VAR_OH] = (int) res == 0 ? inlink->h : (int) res; /* evaluate again the width, as it may depend on the output height */ if ((ret = av_expr_parse_and_eval(&res, (expr = w_expr), - names, var_values, + var_names, var_values, NULL, NULL, NULL, NULL, NULL, 0, log_ctx)) < 0) goto fail; eval_w = (int) res == 0 ? inlink->w : (int) res; diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c index 41ddec7661..e7d52faccc 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,6 +41,85 @@ #include "libavutil/avassert.h" #include "libswscale/swscale.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 +}; + +/** + * This must be kept in sync with var_names so that it is always a + * complete list of var_names with the scale2ref specific names + * appended. scale2ref values must appear in the order they appear + * in the var_name_scale2ref enum but also be below all of the + * non-scale2ref specific values. + */ +static const char *const var_names_scale2ref[] = { + "PI", + "PHI", + "E", + "in_w", "iw", + "in_h", "ih", + "out_w", "ow", + "out_h", "oh", + "a", + "sar", + "dar", + "hsub", + "vsub", + "ohsub", + "ovsub", + "main_w", + "main_h", + "main_a", + "main_sar", + "main_dar", "mdar", + "main_hsub", + "main_vsub", + NULL +}; + +enum var_name_scale2ref { + VAR_S2R_MAIN_W, + VAR_S2R_MAIN_H, + VAR_S2R_MAIN_A, + VAR_S2R_MAIN_SAR, + VAR_S2R_MAIN_DAR, VAR_S2R_MDAR, + VAR_S2R_MAIN_HSUB, + VAR_S2R_MAIN_VSUB, + VARS_S2R_NB +}; + enum EvalMode { EVAL_MODE_INIT, EVAL_MODE_FRAME, @@ -218,6 +297,115 @@ static const int *parse_yuv_type(const char *s, enum AVColorSpace colorspace) return sws_getCoefficients(colorspace); } +static int scale_eval_dimensions(void *log_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; + const char scale2ref = outlink->src->nb_inputs == 2 && outlink->src->inputs[1] == inlink; + double var_values[VARS_NB + VARS_S2R_NB], res; + const AVPixFmtDescriptor *main_desc; + const AVFilterLink *main_link; + const char *const *names = scale2ref ? var_names_scale2ref : var_names; + + if (scale2ref) { + main_link = outlink->src->inputs[0]; + main_desc = av_pix_fmt_desc_get(main_link->format); + } + + 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]; + 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; + + if (scale2ref) { + var_values[VARS_NB + VAR_S2R_MAIN_W] = main_link->w; + var_values[VARS_NB + VAR_S2R_MAIN_H] = main_link->h; + var_values[VARS_NB + VAR_S2R_MAIN_A] = (double) main_link->w / main_link->h; + var_values[VARS_NB + VAR_S2R_MAIN_SAR] = main_link->sample_aspect_ratio.num ? + (double) main_link->sample_aspect_ratio.num / main_link->sample_aspect_ratio.den : 1; + var_values[VARS_NB + VAR_S2R_MAIN_DAR] = var_values[VARS_NB + VAR_S2R_MDAR] = + var_values[VARS_NB + VAR_S2R_MAIN_A] * var_values[VARS_NB + VAR_S2R_MAIN_SAR]; + var_values[VARS_NB + VAR_S2R_MAIN_HSUB] = 1 << main_desc->log2_chroma_w; + var_values[VARS_NB + VAR_S2R_MAIN_VSUB] = 1 << main_desc->log2_chroma_h; + } + + /* evaluate width and height */ + av_expr_parse_and_eval(&res, (expr = w_expr), + names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, log_ctx); + eval_w = var_values[VAR_OUT_W] = var_values[VAR_OW] = (int) res == 0 ? inlink->w : (int) res; + + if ((ret = av_expr_parse_and_eval(&res, (expr = h_expr), + names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, log_ctx)) < 0) + goto fail; + eval_h = var_values[VAR_OUT_H] = var_values[VAR_OH] = (int) res == 0 ? inlink->h : (int) res; + /* evaluate again the width, as it may depend on the output height */ + if ((ret = av_expr_parse_and_eval(&res, (expr = w_expr), + names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, log_ctx)) < 0) + goto fail; + eval_w = (int) res == 0 ? inlink->w : (int) 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) { + w = inlink->w; + 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(log_ctx, 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; +} + static int config_props(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; @@ -231,7 +419,7 @@ static int config_props(AVFilterLink *outlink) int w, h; int ret; - if ((ret = ff_scale_eval_dimensions(ctx, + if ((ret = scale_eval_dimensions(ctx, scale->w_expr, scale->h_expr, inlink, outlink, &w, &h)) < 0)