summaryrefslogtreecommitdiff
path: root/libavfilter/f_sendcmd.c
diff options
context:
space:
mode:
authorPaul B Mahol <onemda@gmail.com>2020-02-28 23:11:32 +0100
committerPaul B Mahol <onemda@gmail.com>2020-03-03 20:38:56 +0100
commit70209000fd1c7033b2039f4c906d0d0c6cd500b4 (patch)
tree5fa911e028e9a8e74fb3dd0c6eaca045ba6d805b /libavfilter/f_sendcmd.c
parent3117f47f19d051d47ba29c9b78c2ca525f0fdb45 (diff)
avfilter/f_sendcmd: implement expr flag
Make possible to parse expressions and store results as arguments for target filters.
Diffstat (limited to 'libavfilter/f_sendcmd.c')
-rw-r--r--libavfilter/f_sendcmd.c54
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);
}
}
}