[FFmpeg-devel] [PATCH] avfilter/sine: support expression in the number of output samples

Clément Bœsch u at pkh.me
Sat Aug 15 19:22:15 CEST 2015


---
Seems a bit tricky to do it in asetnsamples so... Might be relevant to do the
same in aevalsrc as well.
---
 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 2dd7d22..332a468 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:
+
+ at table @option
+ at item n
+The (sequential) number of the output audio frame, starting from 0.
+
+ at item pts
+The PTS (Presentation TimeStamp) of the output audio frame,
+expressed in @var{TB} units.
+
+ at item t
+The PTS of the output audio frame, expressed in seconds.
+
+ at item TB
+The timebase of the output audio frames.
+ at 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
 
+ at item
+Generate a 1 kHz sine wave following @code{1602,1601,1602,1601,1602} NTSC
+pattern:
+ at example
+sine=1000:samples_per_frame='st(0,mod(n,5)); 1602-not(not(eq(ld(0),1)+eq(ld(0),3)))'
+ at end example
 @end itemize
 
 @c man end AUDIO SOURCES
diff --git a/libavfilter/asrc_sine.c b/libavfilter/asrc_sine.c
index 6aa01d5..cd43ae4 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);
-- 
2.5.0



More information about the ffmpeg-devel mailing list