mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-01-13 21:28:01 +02:00
avfilter/f_sendcmd: implement expr flag
Make possible to parse expressions and store results as arguments for target filters.
This commit is contained in:
parent
3117f47f19
commit
70209000fd
@ -23666,6 +23666,29 @@ The command is sent when the current frame timestamp leaves the
|
||||
specified interval. In other words, the command is sent when the
|
||||
previous frame timestamp was in the given interval, and the
|
||||
current is not.
|
||||
|
||||
@item expr
|
||||
The command @var{ARG} is interpreted as expression and result of
|
||||
expression is passed as @var{ARG}.
|
||||
|
||||
The expression is evaluated through the eval API and can contain the following
|
||||
constants:
|
||||
|
||||
@table @option
|
||||
@item POS
|
||||
Original position in the file of the frame, or undefined if undefined
|
||||
for the current frame.
|
||||
|
||||
@item PTS
|
||||
The presentation timestamp in input.
|
||||
|
||||
@item N
|
||||
The count of the input frame for video or audio, starting from 0.
|
||||
|
||||
@item T
|
||||
The time in seconds of the current frame.
|
||||
@end table
|
||||
|
||||
@end table
|
||||
|
||||
If @var{FLAGS} is not specified, a default value of @code{[enter]} is
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user