From: Simon Binder <oss@simonbinder.eu> To: ffmpeg-devel@ffmpeg.org Subject: [FFmpeg-devel] [PATCH] avfilter/vf_perspective: Add support for commands Date: Thu, 31 Mar 2022 20:54:42 +0000 Message-ID: <11d5064c-86b4-ff71-d8fd-b7f984005d86@simonbinder.eu> (raw) Store expressions to avoid parsing them for each change. Support a command re-assigning all corners for the perspective. Signed-off-by: Simon Binder <oss@simonbinder.eu> --- doc/filters.texi | 13 ++++ libavfilter/vf_perspective.c | 114 ++++++++++++++++++++++++++++------- 2 files changed, 106 insertions(+), 21 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index 1d56d24819..4fe4dc04d9 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -17201,6 +17201,19 @@ evaluate expressions for each incoming frame Default value is @samp{init}. @end table +@subsection Commands + +This filter supports the following command: + +@table @option +@item dims +Updates all eight coordinate values from one colon-separated parameter. +@example +0.0 [enter] perspective dims 0:0:300:0:0:300:300:300; +5.0 [enter] perspective dims 0:0:300:50:0:300:300:350; +@end example +@end table + @section phase Delay interlaced video by one field time so that the field order changes. diff --git a/libavfilter/vf_perspective.c b/libavfilter/vf_perspective.c index da720dcb54..e81234c7d6 100644 --- a/libavfilter/vf_perspective.c +++ b/libavfilter/vf_perspective.c @@ -19,13 +19,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <libavutil/avstring.h> #include "libavutil/avassert.h" #include "libavutil/eval.h" #include "libavutil/imgutils.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" -#include "formats.h" #include "internal.h" #include "video.h" @@ -36,9 +36,13 @@ #define LINEAR 0 #define CUBIC 1 +static const char *const var_names[] = { "W", "H", "in", "on", NULL }; +enum { VAR_W, VAR_H, VAR_IN, VAR_ON, VAR_VARS_NB }; + typedef struct PerspectiveContext { const AVClass *class; char *expr_str[4][2]; + AVExpr* expr[4][2]; double ref[4][2]; int32_t (*pv)[2]; int32_t coeff[SUB_PIXELS][4]; @@ -49,6 +53,7 @@ typedef struct PerspectiveContext { int nb_planes; int sense; int eval_mode; + double var_values[VAR_VARS_NB]; int (*perspective)(AVFilterContext *ctx, void *arg, int job, int nb_jobs); @@ -117,34 +122,31 @@ static inline double get_coeff(double d) return coeff; } -static const char *const var_names[] = { "W", "H", "in", "on", NULL }; -enum { VAR_W, VAR_H, VAR_IN, VAR_ON, VAR_VARS_NB }; - -static int calc_persp_luts(AVFilterContext *ctx, AVFilterLink *inlink) +static void set_variables_for_link(AVFilterContext *ctx, AVFilterLink *inlink) { PerspectiveContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; + + s->var_values[VAR_W] = inlink->w; + s->var_values[VAR_H] = inlink->h; + s->var_values[VAR_IN] = inlink->frame_count_out + 1; + s->var_values[VAR_ON] = outlink->frame_count_in + 1; +} + +static int calc_persp_luts(AVFilterContext *ctx) +{ + PerspectiveContext *s = ctx->priv; double (*ref)[2] = s->ref; - double values[VAR_VARS_NB] = { [VAR_W] = inlink->w, [VAR_H] = inlink->h, - [VAR_IN] = inlink->frame_count_out + 1, - [VAR_ON] = outlink->frame_count_in + 1 }; - const int h = values[VAR_H]; - const int w = values[VAR_W]; + const int h = s->var_values[VAR_H]; + const int w = s->var_values[VAR_W]; double x0, x1, x2, x3, x4, x5, x6, x7, x8, q; double t0, t1, t2, t3; - int x, y, i, j, ret; + int x, y, i, j; for (i = 0; i < 4; i++) { for (j = 0; j < 2; j++) { - if (!s->expr_str[i][j]) - return AVERROR(EINVAL); - ret = av_expr_parse_and_eval(&s->ref[i][j], s->expr_str[i][j], - var_names, &values[0], - NULL, NULL, NULL, NULL, - 0, 0, ctx); - if (ret < 0) - return ret; + s->ref[i][j] = av_expr_eval(s->expr[i][j], s->var_values, s); } } @@ -238,8 +240,27 @@ static int config_input(AVFilterLink *inlink) if (!s->pv) return AVERROR(ENOMEM); + // Parse coordinate expressions + for (i = 0; i < 4; i++) { + for (j = 0; j < 2; j++) { + av_expr_free(s->expr[i][j]); + s->expr[i][j] = NULL; + + if (!s->expr_str[i][j]) + return AVERROR(EINVAL); + + if ((ret = av_expr_parse(&s->expr[i][j], s->expr_str[i][j], var_names, + NULL, NULL, NULL, NULL, 0, ctx)) < 0) { + av_log(ctx, AV_LOG_ERROR, + "Error occurred parsing coordinate '%s'\n", s->expr_str[i][j]); + return ret; + } + } + } + if (s->eval_mode == EVAL_MODE_INIT) { - if ((ret = calc_persp_luts(ctx, inlink)) < 0) { + set_variables_for_link(ctx, inlink); + if ((ret = calc_persp_luts(ctx)) < 0) { return ret; } } @@ -437,6 +458,49 @@ static av_cold int init(AVFilterContext *ctx) return 0; } +static int process_command(AVFilterContext *ctx, const char *cmd, const char *arg, + char *res, int res_len, int flags) +{ + PerspectiveContext *s = ctx->priv; + int ret; + char *token; + AVExpr *old; + + if (!strcmp(cmd, "dims")) { + // Expect arg to be an 8-token argument containing the new coordinates + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 2; j++) { + if (!*arg) { + av_log(ctx, AV_LOG_ERROR,"Expected 8 expressions for the new coordinates\n"); + return AVERROR(EINVAL); + } + + token = av_get_token(&arg, ":"); + if (!token) + return AVERROR(ENOMEM); + arg++; + + old = s->expr[i][j]; + + if ((ret = av_expr_parse(&s->expr[i][j], token, var_names, + NULL, NULL, NULL, NULL, 0, ctx)) < 0) { + av_log(ctx, AV_LOG_ERROR, + "Error occurred parsing coordinate '%s'\n", token); + av_free(token); + return ret; + } + av_free(token); + av_expr_free(old); + } + } + + ret = calc_persp_luts(ctx); + } else + ret = AVERROR(ENOSYS); + + return ret; +} + static int filter_frame(AVFilterLink *inlink, AVFrame *frame) { AVFilterContext *ctx = inlink->dst; @@ -454,7 +518,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) av_frame_copy_props(out, frame); if (s->eval_mode == EVAL_MODE_FRAME) { - if ((ret = calc_persp_luts(ctx, inlink)) < 0) { + set_variables_for_link(ctx, inlink); + if ((ret = calc_persp_luts(ctx)) < 0) { av_frame_free(&out); return ret; } @@ -484,6 +549,12 @@ static av_cold void uninit(AVFilterContext *ctx) PerspectiveContext *s = ctx->priv; av_freep(&s->pv); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 2; j++) { + av_expr_free(s->expr[i][j]); + s->expr[i][j] = NULL; + } + } } static const AVFilterPad perspective_inputs[] = { @@ -508,6 +579,7 @@ const AVFilter ff_vf_perspective = { .priv_size = sizeof(PerspectiveContext), .init = init, .uninit = uninit, + .process_command = &process_command, FILTER_INPUTS(perspective_inputs), FILTER_OUTPUTS(perspective_outputs), FILTER_PIXFMTS_ARRAY(pix_fmts), -- 2.35.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
reply other threads:[~2022-03-31 20:54 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=11d5064c-86b4-ff71-d8fd-b7f984005d86@simonbinder.eu \ --to=oss@simonbinder.eu \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git