]> git.sesse.net Git - ffmpeg/blobdiff - libavfilter/f_sendcmd.c
avfilter: Constify all AVFilters
[ffmpeg] / libavfilter / f_sendcmd.c
index b8740e888303ac6893508cd1a640e09af4083ab1..71b0a5c41102e2b347569f3125dfa19f921b20ba 100644 (file)
@@ -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"
 
 #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,