[FFmpeg-devel] [PATCH 2/2] lavfi/setpts: introduce rand() function in expression

Stefano Sabatini stefasab at gmail.com
Thu Dec 28 02:38:39 EET 2023


This is useful to simulate random jitter.
---
 Changelog            |  1 +
 doc/filters.texi     | 10 +++++++++-
 libavfilter/setpts.c | 39 +++++++++++++++++++++++++++++++++------
 3 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/Changelog b/Changelog
index 424bfc11af..ed01c53264 100644
--- a/Changelog
+++ b/Changelog
@@ -15,6 +15,7 @@ version <next>:
 - tiltandshift filter
 - qrencode filter and qrencodesrc source
 - quirc filter
+- lavfi/setpts: introduce rand() function in expression
 
 version 6.1:
 - libaribcaption decoder
diff --git a/doc/filters.texi b/doc/filters.texi
index d1f95b9781..1d9a5d6c7d 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -30946,7 +30946,7 @@ The expression which is evaluated for each frame to construct its timestamp.
 @end table
 
 The expression is evaluated through the eval API and can contain the following
-constants:
+constants and functions:
 
 @table @option
 @item FRAME_RATE, FR
@@ -31010,6 +31010,8 @@ The timebase of the input timestamps.
 @item T_CHANGE
 Time of the first frame after command was applied or time of the first frame if no commands.
 
+ at item rand(min, max)
+a random number included between min and max
 @end table
 
 @subsection Examples
@@ -31021,6 +31023,12 @@ Start counting PTS from zero
 setpts=PTS-STARTPTS
 @end example
 
+ at item
+Apply a random jitter effect of +/-100 TB units:
+ at example
+setpts=PTS+100rand(-100\,100)
+ at end example
+
 @item
 Apply fast motion effect:
 @example
diff --git a/libavfilter/setpts.c b/libavfilter/setpts.c
index 88a8d6af86..0f24a900b3 100644
--- a/libavfilter/setpts.c
+++ b/libavfilter/setpts.c
@@ -32,6 +32,8 @@
 #include "libavutil/internal.h"
 #include "libavutil/mathematics.h"
 #include "libavutil/opt.h"
+#include "libavutil/lfg.h"
+#include "libavutil/random_seed.h"
 #include "libavutil/time.h"
 #include "audio.h"
 #include "avfilter.h"
@@ -101,18 +103,39 @@ typedef struct SetPTSContext {
     AVExpr *expr;
     double var_values[VAR_VARS_NB];
     enum AVMediaType type;
+    AVLFG lfg;
 } SetPTSContext;
 
 #define V(name_) \
     setpts->var_values[VAR_##name_]
 
+static double drand(void *ctx, double min, double max)
+{
+    SetPTSContext *setpts = ((AVFilterContext *)ctx)->priv;
+
+    return min + (max-min) / UINT_MAX * av_lfg_get(&setpts->lfg);
+}
+
+typedef double (*eval_func2)(void *, double a, double b);
+
+static const eval_func2 fun2[] = {
+    drand,
+    NULL
+};
+
+static const char *const fun2_names[] = {
+    "rand"
+};
+
 static av_cold int init(AVFilterContext *ctx)
 {
     SetPTSContext *setpts = ctx->priv;
     int ret;
 
+    av_lfg_init(&setpts->lfg, av_get_random_seed());
+
     if ((ret = av_expr_parse(&setpts->expr, setpts->expr_str,
-                             var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
+                             var_names, NULL, NULL, fun2_names, fun2, 0, ctx)) < 0) {
         av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n", setpts->expr_str);
         return ret;
     }
@@ -126,6 +149,7 @@ static av_cold int init(AVFilterContext *ctx)
     V(STARTPTS)    = NAN;
     V(STARTT)      = NAN;
     V(T_CHANGE)    = NAN;
+
     return 0;
 }
 
@@ -159,8 +183,10 @@ static inline char *double2int64str(char *buf, double v)
     return buf;
 }
 
-static double eval_pts(SetPTSContext *setpts, AVFilterLink *inlink, AVFrame *frame, int64_t pts)
+static double eval_pts(AVFilterContext *ctx, AVFilterLink *inlink, AVFrame *frame, int64_t pts)
 {
+    SetPTSContext *setpts = ctx->priv;
+
     if (isnan(V(STARTPTS))) {
         V(STARTPTS) = TS2D(pts);
         V(STARTT  ) = TS2T(pts, inlink->time_base);
@@ -186,17 +212,18 @@ FF_ENABLE_DEPRECATION_WARNINGS
         }
     }
 
-    return av_expr_eval(setpts->expr, setpts->var_values, NULL);
+    return av_expr_eval(setpts->expr, setpts->var_values, ctx);
 }
 #define d2istr(v) double2int64str((char[BUF_SIZE]){0}, v)
 
 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
-    SetPTSContext *setpts = inlink->dst->priv;
+    AVFilterContext *ctx = inlink->dst;
+    SetPTSContext *setpts = ctx->priv;
     int64_t in_pts = frame->pts;
     double d;
 
-    d = eval_pts(setpts, inlink, frame, frame->pts);
+    d = eval_pts(ctx, inlink, frame, frame->pts);
     frame->pts = D2TS(d);
 
     av_log(inlink->dst, AV_LOG_TRACE,
@@ -250,7 +277,7 @@ static int activate(AVFilterContext *ctx)
         return filter_frame(inlink, in);
 
     if (ff_inlink_acknowledge_status(inlink, &status, &pts)) {
-        double d = eval_pts(setpts, inlink, NULL, pts);
+        double d = eval_pts(ctx, inlink, NULL, pts);
 
         av_log(ctx, AV_LOG_TRACE, "N:EOF PTS:%s T:%f -> PTS:%s T:%f\n",
                d2istr(V(PTS)), V(T), d2istr(d), TS2T(d, inlink->time_base));
-- 
2.34.1



More information about the ffmpeg-devel mailing list