diff options
author | Paul B Mahol <onemda@gmail.com> | 2020-02-29 01:11:32 +0300 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2020-03-03 22:38:56 +0300 |
commit | 70209000fd1c7033b2039f4c906d0d0c6cd500b4 (patch) | |
tree | 5fa911e028e9a8e74fb3dd0c6eaca045ba6d805b /libavfilter | |
parent | 3117f47f19d051d47ba29c9b78c2ca525f0fdb45 (diff) |
avfilter/f_sendcmd: implement expr flag
Make possible to parse expressions and store results as arguments
for target filters.
Diffstat (limited to 'libavfilter')
-rw-r--r-- | libavfilter/f_sendcmd.c | 54 |
1 files changed, 51 insertions, 3 deletions
diff --git a/libavfilter/f_sendcmd.c b/libavfilter/f_sendcmd.c index b8740e8883..5a62a338ee 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,27 @@ #define COMMAND_FLAG_ENTER 1 #define COMMAND_FLAG_LEAVE 2 +#define COMMAND_FLAG_EXPR 4 + +static const char *const var_names[] = { + "N", /* frame number */ + "T", /* frame time in seconds */ + "POS", /* original position in the file of the frame */ + "PTS", /* frame pts */ + NULL +}; + +enum var_name { + VAR_N, + VAR_T, + VAR_POS, + VAR_PTS, + 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 +147,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 +469,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 +498,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 +511,43 @@ 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_POS] = ref->pkt_pos == -1 ? NAN : ref->pkt_pos; + 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); + av_frame_free(&ref); + return AVERROR(EINVAL); + } + + cmd_arg = av_asprintf("%g", res); + if (!cmd_arg) { + av_frame_free(&ref); + 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); } } } |