X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavfilter%2Ff_sendcmd.c;h=71b0a5c41102e2b347569f3125dfa19f921b20ba;hb=a04ad248a05e7b613abe09b3bb067f555108d794;hp=b8740e888303ac6893508cd1a640e09af4083ab1;hpb=fbd607dd560afe44c3b90de1e6cbe5265cac8f1e;p=ffmpeg diff --git a/libavfilter/f_sendcmd.c b/libavfilter/f_sendcmd.c index b8740e88830..71b0a5c4110 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,33 @@ #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 */ + "TS", /* interval start time in seconds */ + "TE", /* interval end time in seconds */ + "TI", /* interval interpolated value: TI = (T - TS) / (TE - TS) */ + NULL +}; + +enum var_name { + VAR_N, + VAR_T, + VAR_POS, + VAR_PTS, + VAR_TS, + VAR_TE, + VAR_TI, + 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 +153,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)); @@ -476,6 +501,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 +514,49 @@ 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; + double start = TS2T(interval->start_ts, AV_TIME_BASE_Q); + double end = TS2T(interval->end_ts, AV_TIME_BASE_Q); + double current = TS2T(ref->pts, inlink->time_base); + + 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] = current; + var_values[VAR_TS] = start; + var_values[VAR_TE] = end; + var_values[VAR_TI] = (current - start) / (end - start); + + 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); } } } @@ -537,7 +594,7 @@ static const AVFilterPad sendcmd_outputs[] = { { NULL } }; -AVFilter ff_vf_sendcmd = { +const AVFilter ff_vf_sendcmd = { .name = "sendcmd", .description = NULL_IF_CONFIG_SMALL("Send commands to filters."), .init = init, @@ -572,7 +629,7 @@ static const AVFilterPad asendcmd_outputs[] = { { NULL } }; -AVFilter ff_af_asendcmd = { +const AVFilter ff_af_asendcmd = { .name = "asendcmd", .description = NULL_IF_CONFIG_SMALL("Send commands to filters."), .init = init,