From patchwork Fri Feb 28 22:29:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 17968 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 E09AA448844 for ; Sat, 29 Feb 2020 00:55:09 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id B7F6F68B0F2; Sat, 29 Feb 2020 00:55:09 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wr1-f66.google.com (mail-wr1-f66.google.com [209.85.221.66]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id DDCDE68AFFE for ; Sat, 29 Feb 2020 00:55:02 +0200 (EET) Received: by mail-wr1-f66.google.com with SMTP id m16so4906687wrx.11 for ; Fri, 28 Feb 2020 14:55:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id; bh=fRpbtWABoI8jTZTdRo3KKTbQ3EcJ1YvNHMMQaX/EkuE=; b=JjQxb04CGfwsRTXopakFlSIvlAvziJff5zeMKC6+yr75eLgbNXgjgRDUYmJh3ophYt IoKcyxjHjUjPKfQvihAWxqdi53RVpFOXDHq0DAnheQLTjoB0gp/FP+1ufWMwLYa+G2lh 3lABG+5xlhl2Fw4Pp+3QXFdAB9lHeafxeZw+HhnhizRnWj1PoTqapuduQLv7ogzXuLCE 7mwfxFt/k3k/OdYOUXwqO6iLiRb3o0Kw9vQWu8N0T5guwqMq2J7SpYcVWstzBlG2Vvil FGQiRq/GQB6Eyj+S7RCa9ofxDHjkGiJK0ztqb2hjfHJ+3fHLSB83zEARSeSjbjTtCM02 ConA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id; bh=fRpbtWABoI8jTZTdRo3KKTbQ3EcJ1YvNHMMQaX/EkuE=; b=sRYAJdckMhsAwwTKuc+vbJPMpfKgrR4c1nfyFuZQw2Eegg/3ZqzKgTb+zAhFKFWZy7 T6uBrJaEoPcQXuZPfE8ioki0kprWexRSjlokrKGbL1jGOOR/TxIDN1/KU90I/WJ6ZJmZ gFT/WyIKjbAhhvjOvQUbXXhL5Lw+noIl1nuvzbb28ZwoesLyFARUpyG3Nx8hHR4axdWZ EuRile64vMq5YnO2jTWBKezdpuQFt4O4cac4+XPE4J+j1ZaQYbVHzWhJEkSIPzOvc7BR hiBJJWLEJl9OykFXkN96oL/G7tSNKm9AzR7fgVMQp/a5bQzwrFRXhLyf+c6glL6/jn+n QP2g== X-Gm-Message-State: APjAAAUAGW/cg2fxAIQdS6vFGlY99/PHKdAp0F3m+F3WsWnj/SaVN6gV SEfqzPwyBo5V0XIdjRDq/pZNLlhN X-Google-Smtp-Source: APXvYqxFzWXYaS89QY7JLE5DaOJPP6bsIl8qhfl14o6Hd5Jp+Uf/QsiEQJFXQm01neeqUaM5q10eTw== X-Received: by 2002:a05:6000:106:: with SMTP id o6mr6631131wrx.120.1582928985540; Fri, 28 Feb 2020 14:29:45 -0800 (PST) Received: from localhost.localdomain ([109.227.48.215]) by smtp.gmail.com with ESMTPSA id m19sm4012187wmc.34.2020.02.28.14.29.43 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Feb 2020 14:29:44 -0800 (PST) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Fri, 28 Feb 2020 23:29:35 +0100 Message-Id: <20200228222935.24998-1-onemda@gmail.com> X-Mailer: git-send-email 2.17.1 Subject: [FFmpeg-devel] [PATCH] avfilter/f_sendcmd: implement expr flag 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 MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Make possible to parse expressions and store results as arguments for target filters. Signed-off-by: Paul B Mahol --- doc/filters.texi | 19 ++++++++++++++++ libavfilter/f_sendcmd.c | 48 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index 1453ecd8b1..30a7b77b4f 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -23659,6 +23659,25 @@ The command is sent when the current frame timestamp leaves the specified interval. In other words, the command is sent when the previous frame timestamp was in the given interval, and the current is not. + +@item expr +The command @var{ARG} is interpreted as expression and result of +expression is passed as @var{ARG}. + +The expression is evaluated through the eval API and can contain the following +constants: + +@table @option +@item PTS +The presentation timestamp in input. + +@item N +The count of the input frame for video or audio, starting from 0. + +@item T +The time in seconds of the current frame. +@end table + @end table If @var{FLAGS} is not specified, a default value of @code{[enter]} is diff --git a/libavfilter/f_sendcmd.c b/libavfilter/f_sendcmd.c index b8740e8883..81b424a3f0 100644 --- a/libavfilter/f_sendcmd.c +++ b/libavfilter/f_sendcmd.c @@ -25,6 +25,7 @@ #include "libavutil/avstring.h" #include "libavutil/bprint.h" +#include "libavutil/eval.h" #include "libavutil/file.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" @@ -35,10 +36,25 @@ #define COMMAND_FLAG_ENTER 1 #define COMMAND_FLAG_LEAVE 2 +#define COMMAND_FLAG_EXPR 4 + +static const char *const var_names[] = { + "T", /* frame time in seconds */ + "PTS", /* frame pts */ + "N", /* frame number */ + NULL +}; + +enum var_name { + VAR_T, + VAR_PTS, + VAR_N, + VAR_VARS_NB +}; static inline char *make_command_flags_str(AVBPrint *pbuf, int flags) { - static const char * const flag_strings[] = { "enter", "leave" }; + static const char * const flag_strings[] = { "enter", "leave", "expr" }; int i, is_first = 1; av_bprint_init(pbuf, 0, AV_BPRINT_SIZE_AUTOMATIC); @@ -129,6 +145,7 @@ static int parse_command(Command *cmd, int cmd_count, int interval_count, if (!strncmp(*buf, "enter", strlen("enter"))) cmd->flags |= COMMAND_FLAG_ENTER; else if (!strncmp(*buf, "leave", strlen("leave"))) cmd->flags |= COMMAND_FLAG_LEAVE; + else if (!strncmp(*buf, "expr", strlen("expr"))) cmd->flags |= COMMAND_FLAG_EXPR; else { char flag_buf[64]; av_strlcpy(flag_buf, *buf, sizeof(flag_buf)); @@ -450,6 +467,9 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&s->intervals); } +#define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts)) +#define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts)*av_q2d(tb)) + static int filter_frame(AVFilterLink *inlink, AVFrame *ref) { AVFilterContext *ctx = inlink->dst; @@ -476,6 +496,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *ref) flags += COMMAND_FLAG_LEAVE; interval->enabled = 0; } + if (interval->enabled) + flags += COMMAND_FLAG_EXPR; if (flags) { AVBPrint pbuf; @@ -487,19 +509,39 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *ref) for (j = 0; flags && j < interval->nb_commands; j++) { Command *cmd = &interval->commands[j]; + char *cmd_arg = cmd->arg; char buf[1024]; if (cmd->flags & flags) { + if ((cmd->flags & COMMAND_FLAG_EXPR)) { + double var_values[VAR_VARS_NB], res; + + var_values[VAR_N] = inlink->frame_count_in; + var_values[VAR_PTS] = TS2D(ref->pts); + var_values[VAR_T] = TS2T(ref->pts, inlink->time_base); + + if ((ret = av_expr_parse_and_eval(&res, cmd->arg, var_names, var_values, + NULL, NULL, NULL, NULL, NULL, 0, NULL)) < 0) { + av_log(ctx, AV_LOG_ERROR, "Invalid expression '%s' for command argument.\n", cmd->arg); + return AVERROR(EINVAL); + } + + cmd_arg = av_asprintf("%g", res); + if (!cmd_arg) + return AVERROR(ENOMEM); + } av_log(ctx, AV_LOG_VERBOSE, "Processing command #%d target:%s command:%s arg:%s\n", - cmd->index, cmd->target, cmd->command, cmd->arg); + cmd->index, cmd->target, cmd->command, cmd_arg); ret = avfilter_graph_send_command(inlink->graph, - cmd->target, cmd->command, cmd->arg, + cmd->target, cmd->command, cmd_arg, buf, sizeof(buf), AVFILTER_CMD_FLAG_ONE); av_log(ctx, AV_LOG_VERBOSE, "Command reply for command #%d: ret:%s res:%s\n", cmd->index, av_err2str(ret), buf); + if ((cmd->flags & COMMAND_FLAG_EXPR)) + av_freep(&cmd_arg); } } }