From a388ca359d78c6fa00c75b326ada11048b1226ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20B=C5=93sch?= Date: Mon, 10 Aug 2015 21:03:11 +0200 Subject: [PATCH] avfilter/sine: support expression in the number of output samples --- doc/filters.texi | 27 ++++++++++++++++++++++- libavfilter/asrc_sine.c | 48 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index d506d68a5e..7b9d665aea 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -2857,7 +2857,26 @@ Specify the sample rate, default is 44100. Specify the duration of the generated audio stream. @item samples_per_frame -Set the number of samples per output frame, default is 1024. +Set the number of samples per output frame. + +The expression can contain the following constants: + +@table @option +@item n +The (sequential) number of the output audio frame, starting from 0. + +@item pts +The PTS (Presentation TimeStamp) of the output audio frame, +expressed in @var{TB} units. + +@item t +The PTS of the output audio frame, expressed in seconds. + +@item TB +The timebase of the output audio frames. +@end table + +Default is @code{1024}. @end table @subsection Examples @@ -2878,6 +2897,12 @@ sine=f=220:b=4:d=5 sine=frequency=220:beep_factor=4:duration=5 @end example +@item +Generate a 1 kHz sine wave following @code{1602,1601,1602,1601,1602} NTSC +pattern: +@example +sine=1000:samples_per_frame='st(0,mod(n,5)); 1602-not(not(eq(ld(0),1)+eq(ld(0),3)))' +@end example @end itemize @c man end AUDIO SOURCES diff --git a/libavfilter/asrc_sine.c b/libavfilter/asrc_sine.c index 6aa01d5ec5..cd43ae444e 100644 --- a/libavfilter/asrc_sine.c +++ b/libavfilter/asrc_sine.c @@ -22,6 +22,7 @@ #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" +#include "libavutil/eval.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" @@ -31,7 +32,8 @@ typedef struct { const AVClass *class; double frequency; double beep_factor; - int samples_per_frame; + char *samples_per_frame; + AVExpr *samples_per_frame_expr; int sample_rate; int64_t duration; int16_t *sin; @@ -61,6 +63,9 @@ typedef struct { #define OPT_DUR(name, field, def, min, max, descr, ...) \ OPT_GENERIC(name, field, def, min, max, descr, DURATION, str, __VA_ARGS__) +#define OPT_STR(name, field, def, min, max, descr, ...) \ + OPT_GENERIC(name, field, def, min, max, descr, STRING, str, __VA_ARGS__) + static const AVOption sine_options[] = { OPT_DBL("frequency", frequency, 440, 0, DBL_MAX, "set the sine frequency"), OPT_DBL("f", frequency, 440, 0, DBL_MAX, "set the sine frequency"), @@ -70,7 +75,7 @@ static const AVOption sine_options[] = { OPT_INT("r", sample_rate, 44100, 1, INT_MAX, "set the sample rate"), OPT_DUR("duration", duration, 0, 0, INT64_MAX, "set the audio duration"), OPT_DUR("d", duration, 0, 0, INT64_MAX, "set the audio duration"), - OPT_INT("samples_per_frame", samples_per_frame, 1024, 0, INT_MAX, "set the number of samples per frame"), + OPT_STR("samples_per_frame", samples_per_frame, "1024", 0, 0, "set the number of samples per frame"), {NULL} }; @@ -120,8 +125,25 @@ static void make_sin_table(int16_t *sin) sin[i + 2 * half_pi] = -sin[i]; } +static const char *const var_names[] = { + "n", + "pts", + "t", + "TB", + NULL +}; + +enum { + VAR_N, + VAR_PTS, + VAR_T, + VAR_TB, + VAR_VARS_NB +}; + static av_cold int init(AVFilterContext *ctx) { + int ret; SineContext *sine = ctx->priv; if (!(sine->sin = av_malloc(sizeof(*sine->sin) << LOG_PERIOD))) @@ -136,6 +158,12 @@ static av_cold int init(AVFilterContext *ctx) sine->sample_rate + 0.5; } + ret = av_expr_parse(&sine->samples_per_frame_expr, + sine->samples_per_frame, var_names, + NULL, NULL, NULL, NULL, 0, sine); + if (ret < 0) + return ret; + return 0; } @@ -143,6 +171,8 @@ static av_cold void uninit(AVFilterContext *ctx) { SineContext *sine = ctx->priv; + av_expr_free(sine->samples_per_frame_expr); + sine->samples_per_frame_expr = NULL; av_freep(&sine->sin); } @@ -188,9 +218,21 @@ static int request_frame(AVFilterLink *outlink) { SineContext *sine = outlink->src->priv; AVFrame *frame; - int i, nb_samples = sine->samples_per_frame; + double values[VAR_VARS_NB] = { + [VAR_N] = outlink->frame_count, + [VAR_PTS] = sine->pts, + [VAR_T] = sine->pts * av_q2d(outlink->time_base), + [VAR_TB] = av_q2d(outlink->time_base), + }; + int i, nb_samples = lrint(av_expr_eval(sine->samples_per_frame_expr, values, sine)); int16_t *samples; + if (nb_samples <= 0) { + av_log(sine, AV_LOG_WARNING, "nb samples expression evaluated to %d, " + "defaulting to 1024\n", nb_samples); + nb_samples = 1024; + } + if (sine->duration) { nb_samples = FFMIN(nb_samples, sine->duration - sine->pts); av_assert1(nb_samples >= 0);