#include "libavutil/avstring.h"
#include "libavutil/bprint.h"
+#include "libavutil/eval.h"
#include "libavutil/file.h"
#include "libavutil/opt.h"
#include "libavutil/parseutils.h"
#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);
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));
flags += COMMAND_FLAG_LEAVE;
interval->enabled = 0;
}
+ if (interval->enabled)
+ flags += COMMAND_FLAG_EXPR;
if (flags) {
AVBPrint pbuf;
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);
}
}
}