|
|
|
@ -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); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|