diff --git a/doc/filters.texi b/doc/filters.texi index 75dd2decdd..55f2062ddc 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -999,7 +999,11 @@ will create 5 copies of the input audio. Forward two audio streams and control the order the buffers are forwarded. -The argument to the filter is an expression deciding which stream should be +The filter accepts the following options: + +@table @option +@item expr, e +Set the expression deciding which stream should be forwarded next: if the result is negative, the first stream is forwarded; if the result is positive or zero, the second stream is forwarded. It can use the following variables: @@ -1015,8 +1019,11 @@ current timestamp of each stream The default value is @code{t1-t2}, which means to always forward the stream that has a smaller timestamp. +@end table -Example: stress-test @code{amerge} by randomly sending buffers on the wrong +@subsection Examples + +Stress-test @code{amerge} by randomly sending buffers on the wrong input, while avoiding too much of a desynchronization: @example amovie=file.ogg [a] ; amovie=file.mp3 [b] ; diff --git a/libavfilter/af_astreamsync.c b/libavfilter/af_astreamsync.c index 76a152c87a..47e66bcc03 100644 --- a/libavfilter/af_astreamsync.c +++ b/libavfilter/af_astreamsync.c @@ -24,6 +24,7 @@ */ #include "libavutil/eval.h" +#include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" #include "internal.h" @@ -45,7 +46,9 @@ enum var_name { }; typedef struct { + const AVClass *class; AVExpr *expr; + char *expr_str; double var_values[VAR_NB]; struct buf_queue { AVFrame *buf[QUEUE_SIZE]; @@ -58,18 +61,25 @@ typedef struct { int eof; /* bitmask, one bit for each stream */ } AStreamSyncContext; -static const char *default_expr = "t1-t2"; +#define OFFSET(x) offsetof(AStreamSyncContext, x) +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM +static const AVOption astreamsync_options[] = { + { "expr", "set stream selection expression", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "t1-t2" }, .flags = FLAGS }, + { "e", "set stream selection expression", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "t1-t2" }, .flags = FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(astreamsync); static av_cold int init(AVFilterContext *ctx, const char *args0) { AStreamSyncContext *as = ctx->priv; - const char *expr = args0 ? args0 : default_expr; int r, i; - r = av_expr_parse(&as->expr, expr, var_names, + r = av_expr_parse(&as->expr, as->expr_str, var_names, NULL, NULL, NULL, NULL, 0, ctx); if (r < 0) { - av_log(ctx, AV_LOG_ERROR, "Error in expression \"%s\"\n", expr); + av_log(ctx, AV_LOG_ERROR, "Error in expression \"%s\"\n", as->expr_str); return r; } for (i = 0; i < 42; i++) @@ -226,4 +236,5 @@ AVFilter avfilter_af_astreamsync = { .query_formats = query_formats, .inputs = astreamsync_inputs, .outputs = astreamsync_outputs, + .priv_class = &astreamsync_class, }; diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index 3c37dee506..04cd9a776a 100644 --- a/libavfilter/avfilter.c +++ b/libavfilter/avfilter.c @@ -679,7 +679,6 @@ static const char *const filters_left_to_update[] = { "anullsrc", "aresample", "asetnsamples", - "astreamsync", "atempo", "bbox", "buffer",