[FFmpeg-devel] [PATCH] lavfi: add asendcmd and sendcmd filters
Clément Bœsch
ubitux at gmail.com
Mon Sep 3 13:32:04 CEST 2012
On Mon, Sep 03, 2012 at 12:28:11PM +0200, Stefano Sabatini wrote:
[...]
> > Even if "filter class" and "specific filter instance" sounds more correct
> > from a developer perspective, would it make more sense to say that it's
> > just the filter name?
> >
>
> > And by the way, how do you identify the different target instances of the
> > same filter? ("volume", "volume1", "volume2", ...?)
>
> Different filters have different instance name (parsed_...), it is not
> still possible to specify the name of an instance in the filter graph.
>
> > > + at var{time} specify the time when the filter command is sent, expressed
> > > +as a time duration.
> > > +
> >
> > Note: as I said on IRC, I really think this should allow frame accurate
> > timing range at some point.
>
> Mixing times and frames is really hard if not impossible.
>
:(
[...]
> From 56bef733a712a8fbca47109ff2183ad3c680a131 Mon Sep 17 00:00:00 2001
> From: Stefano Sabatini <stefasab at gmail.com>
> Date: Mon, 13 Aug 2012 20:13:26 +0200
> Subject: [PATCH] lavfi: add asendcmd and sendcmd filters
>
> ---
> doc/filters.texi | 124 ++++++++++
> libavfilter/Makefile | 2 +
> libavfilter/allfilters.c | 2 +
> libavfilter/f_sendcmd.c | 578 ++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 706 insertions(+), 0 deletions(-)
> create mode 100644 libavfilter/f_sendcmd.c
>
> diff --git a/doc/filters.texi b/doc/filters.texi
> index 712936d..ceef7c2 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -4176,6 +4176,130 @@ tools.
>
> Below is a description of the currently available multimedia filters.
>
> + at section asendcmd, sendcmd
> +
> +Send commands to filters in the filtergraph.
> +
> +These filters read commands to be sent to other filters in the
> +filtergraph.
> +
> + at code{sendcmd} must be inserted between two video filters.
> + at code{asendcmd} works the same way as sendcmd but for audio.
> +
nit+: @code{sendcmd}
> +The specification of commands can be specified in the filter arguments
> +with the @var{commands} option, or in a file specified with the
> + at var{filename} option.
> +
> +Commands are sent the first time when a frame with time greater or
> +equal to the specified command time is processed by the filter.
> +
> +These filters accept the following options:
> + at table @option
> + at item commands, c
> +Set the commands to be read and sent to the other filters.
> + at item filename, f
> +Set the filename of the commands to be read and sent to the other
> +filters.
> + at end table
> +
> + at subsection Commands syntax
> +
> +A commands description consists of a sequence of interval
> +specifications, comprising a list of commands to be specified at
> +particular events relating to that interval.
> +
> +An interval is specified by the following syntax:
> + at example
> + at var{START}[- at var{END} @var{COMMANDS};
Syntax error: ']' expected around "[- at var{END} @var{COMMANDS};"
> + at end example
> +
> +The time interval is specified by the @var{START} and @var{END} times.
> + at var{END} is optional and defaults to the maximum time.
> +
> + at var{COMMANDS} consists of a sequence of one or more command
> +descriptions, separated by ",", relating to that interval.
> +The syntax of a command is given by:
> + at example
> +[@var{FLAGS}] @var{TARGET} @var{COMMAND} @var{ARG}
> + at end example
> +
> + at var{FLAGS} is optional and specifies the type of events relating to
> +the time interval which enable to send the specified command, and must
> +be a sequence of identifier flag separated by "+" and enclosed between
> +"[" and "]".
> +
> +The following flags are recognized:
> + at table @option
> + at item enter
> +The command is sent when the current frame timestamp enters the
> +specified interval. In other words, the command is sent when the
> +previous frame timestamp was not in the given interval, and the
> +current is.
> +
> + at item leave
> +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.
> + at end table
> +
> +If @var{FLAGS} is not specified, a default value of @code{[enter]} is
> +assumed.
> +
> + at var{TARGET} specifies the target of the command, usually the name of
> +the filter class or a specific filter instance.
> +
> + at var{COMMAND} specifies the name of the command for the @var{TARGET}
> +filter instance.
> +
> + at var{ARG} specifies the optional list of argument for the given
> + at var{COMMAND}.
> +
Maybe mention that this one isn't mandatory? (according to my
understanding of the BNF below)
> +Between one interval specification and another, whitespaces, or
> +sequence of characters until the end of line starting with @code{#},
> +are ignored and can be used to annotate comments.
> +
> +A simplified BNF description of the commands specification syntax
> +follows:
> + at example
> + at var{COMMAND_FLAG} ::= "enter" | "leave"
> + at var{COMMAND_FLAGS} ::= @var{COMMAND_FLAG} [+ at var{COMMAND_FLAG}]
> + at var{COMMAND} ::= ["[" @var{COMMAND_FLAGS} "]"] @var{TARGET} @var{COMMAND} [@var{ARG}]
> + at var{COMMANDS} ::= @var{COMMAND} [, at var{COMMANDS}]
> + at var{INTERVAL} ::= @var{START}[- at var{END}] @var{COMMANDS}
> + at var{INTERVALS} ::= @var{INTERVAL}[;@var{INTERVALS}]
> + at end example
> +
> + at subsection Examples
> +
> + at itemize
> + at item
> +Specify audio tempo change at second 4:
> + at example
> +asendcmd=c='4.0 atempo tempo 1.5',atempo
> + at end example
> +
> + at item
> +Specify a list of drawtext commands in a file.
> + at example
> +# show text in the interval 5-10
> +5.0-10.0 [enter] drawtext reinit
> + fontfile=FreeSerif.ttf:x=(w-text_w)/2:y=(h-text_h-line_h)/2:text="hello world",
> + [leave] drawtext reinit fontfile=FreeSerif.ttf:draw=0;
> +
> +# desaturate the image in the interval 15-20
> +15.0-20.0-8.0 [enter] hue reinit s=0,
> + [enter] drawtext reinit "fontsize=25:fontfile=FreeSerif.ttf:text='no color'",
> + [leave] hue reinit s=1,
> + [enter] drawtext reinit "fontfile=FreeSerif.ttf:text='color'";
> + at end example
> +
> +The file containing the list of commands can be specified with:
> + at example
> +sendcmd=f=test.cmd,drawtext=fontfile=FreeSerif.ttf:text='hello world 0',hue
> + at end example
Here we need a dummy arg line for drawtext, where "hello world 0" won't
ever appear, right?
[...]
> +#define COMMAND_DELIMS " \f\t\n\r,;"
> +
> +static int parse_command(Command *cmd, int cmd_count, int interval_count,
> + const char **buf, void *log_ctx)
> +{
> + int ret;
> +
> + memset(cmd, 0, sizeof(Command));
> + cmd->index = cmd_count;
> +
> + /* format: [FLAGS] target command arg */
> + if (**buf)
> + *buf += strspn(*buf, SPACES);
> +
> + /* parse flags */
> + if (**buf == '[') {
> + (*buf)++; /* skip "[" */
> +
> + while (**buf) {
> + int len = strcspn(*buf, "+]");
> +
> + if (!strncmp(*buf, "enter", strlen("enter"))) cmd->flags += COMMAND_FLAG_ENTER;
> + else if (!strncmp(*buf, "leave", strlen("leave"))) cmd->flags += COMMAND_FLAG_LEAVE;
Why += and not |= ?
[...]
> +static int parse_commands(Command **cmds, int *nb_cmds, int interval_count,
> + const char **buf, void *log_ctx)
> +{
> + int cmd_count = 0;
> + int ret, n = 0;
> +
> + *cmds = 0;
> + *nb_cmds = 0;
> +
> + while (1) {
> + Command cmd;
> +
> + if ((ret = parse_command(&cmd, cmd_count, interval_count, buf, log_ctx)) < 0)
> + return ret;
> + cmd_count++;
> +
> + /* (re)allocate commands array if required*/
nit++: "required */"
> + if (*nb_cmds == n) {
> + n = FFMAX(16, 2*n); /* first allocation = 16, or double the number */
> + *cmds = av_realloc_f(*cmds, n, 2*sizeof(Command));
nit: maybe use av_fast_realloc()? (see in lavf/subtitles.c for instance)
> + if (!*cmds) {
> + av_log(log_ctx, AV_LOG_ERROR,
> + "Could not (re)allocate command array\n");
> + return AVERROR(ENOMEM);
> + }
> + }
> +
> + (*cmds)[(*nb_cmds)++] = cmd;
> +
> + if (**buf)
> + *buf += strspn(*buf, SPACES);
> + if (**buf != ';' && **buf != ',') {
> + av_log(log_ctx, AV_LOG_ERROR,
> + "Missing separator or extraneous data found at the end of "
> + "interval #%d, in command #%d\n",
> + interval_count, cmd_count);
> + return AVERROR(EINVAL);
> + }
> + if (**buf == ';')
> + break;
> + if (**buf == ',')
> + (*buf)++;
> + }
> +
> + return 0;
> +}
> +
> +#define DELIMS " \f\t\n\r,;"
> +
> +static int parse_interval(Interval *interval, int interval_count,
> + const char **buf, void *log_ctx)
> +{
> + char *intervalstr;
> + int ret;
> +
> + if (!**buf)
> + return 0;
> +
> + /* reset data */
> + memset(interval, 0, sizeof(Interval));
> + interval->index = interval_count;
> +
> + /* format: INTERVAL COMMANDS */
> +
> + /* parse interval */
> + if (**buf)
> + *buf += strspn(*buf, SPACES);
> + intervalstr = av_get_token(buf, DELIMS);
> + if (intervalstr) {
> + char *start, *end;
> +
> + start = av_strtok(intervalstr, "-", &end);
> + if ((ret = av_parse_time(&(interval->start_ts), start, 1)) < 0) {
the ( ) look uneeded
> + av_log(log_ctx, AV_LOG_ERROR,
> + "Invalid start time specification '%s' in interval #%d\n",
> + start, interval_count);
> + goto end;
> + }
> +
> + if (end) {
> + if ((ret = av_parse_time(&(interval->end_ts), end, 1)) < 0) {
ditto
[...]
> +static int process_frame(AVFilterLink *inlink, AVFilterBufferRef *ref)
> +{
> + AVFilterContext *ctx = inlink->dst;
> + SendCmdContext *sendcmd = ctx->priv;
> + int64_t ts;
> + int i, j, ret;
> + AVRational tb = {1, 1000000};
> +
> + if (ref->pts == AV_NOPTS_VALUE)
> + goto end;
> +
> + ts = av_rescale_q(ref->pts, inlink->time_base, tb);
> +
> + for (i = 0; i < sendcmd->nb_intervals; i++) {
> + Interval *interval = &sendcmd->intervals[i];
> + int flags = 0;
> +
> + if (!interval->enabled && ts >= interval->start_ts && ts <= interval->end_ts) {
> + flags += COMMAND_FLAG_ENTER;
> + interval->enabled = 1;
> + }
> + if (interval->enabled && (ts < interval->start_ts || ts > interval->end_ts)) {
> + flags += COMMAND_FLAG_LEAVE;
> + interval->enabled = 0;
> + }
> +
ditto += vs |=
> + if (flags) {
> + av_log(ctx, AV_LOG_VERBOSE,
> + "[%s] interval #%d start_ts:%f end_ts:%f ts:%f\n",
> + flags2str(flags), interval->index,
> + (double)interval->start_ts/1000000, (double)interval->end_ts/1000000,
> + (double)ts/1000000);
> +
no av_ts2str or related?
[...]
No other comments from me, thanks.
--
Clément B.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 490 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20120903/de57b724/attachment.asc>
More information about the ffmpeg-devel
mailing list