Add setpts filter, ported from the libavfilter soc repo.
authorStefano Sabatini <stefano.sabatini-lala@poste.it>
Tue, 2 Nov 2010 22:29:17 +0000 (22:29 +0000)
committerStefano Sabatini <stefano.sabatini-lala@poste.it>
Tue, 2 Nov 2010 22:29:17 +0000 (22:29 +0000)
Originally committed as revision 25655 to svn://svn.ffmpeg.org/ffmpeg/trunk

Changelog
doc/filters.texi
libavfilter/Makefile
libavfilter/allfilters.c
libavfilter/avfilter.h
libavfilter/vf_setpts.c [new file with mode: 0644]

index 979e713..a95d4a3 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -51,6 +51,7 @@ version <next>:
 - ffmpeg -force_key_frames option added
 - demuxer for receiving raw rtp:// URLs without an SDP description
 - single stream LATM/LOAS decoder
+- setpts filter added
 
 
 version 0.6:
index 2abe099..e090a04 100644 (file)
@@ -502,6 +502,66 @@ settb=2*intb
 settb=AVTB
 @end example
 
+@section setpts
+
+Change the PTS (presentation timestamp) of the input video frames.
+
+Accept in input an expression evaluated through the eval API, which
+can contain the following constants:
+
+@table @option
+@item PTS
+the presentation timestamp in input
+
+@item PI
+Greek PI
+
+@item PHI
+golden ratio
+
+@item E
+Euler number
+
+@item N
+the count of the input frame, starting from 0.
+
+@item STARTPTS
+the PTS of the first video frame
+
+@item INTERLACED
+tell if the current frame is interlaced
+
+@item POS
+original position in the file of the frame, or undefined if undefined
+for the current frame
+
+@item PREV_INPTS
+previous input PTS
+
+@item PREV_OUTPTS
+previous output PTS
+
+@end table
+
+Some examples follow:
+
+@example
+# start counting PTS from zero
+setpts=PTS-STARTPTS
+
+# fast motion
+setpts=0.5*PTS
+
+# slow motion
+setpts=2.0*PTS
+
+# fixed rate 25 fps
+setpts=N/(25*TB)
+
+# fixed rate 25 fps with some jitter
+setpts='1/(25*TB) * (N + 0.05 * sin(N*2*PI/25))'
+@end example
+
 @section slicify
 
 Pass the images of input video on to next video filter as multiple
index 38d2762..9dc92be 100644 (file)
@@ -37,6 +37,7 @@ OBJS-$(CONFIG_PIXDESCTEST_FILTER)            += vf_pixdesctest.o
 OBJS-$(CONFIG_PIXELASPECT_FILTER)            += vf_aspect.o
 OBJS-$(CONFIG_SCALE_FILTER)                  += vf_scale.o
 OBJS-$(CONFIG_SETTB_FILTER)                  += vf_settb.o
+OBJS-$(CONFIG_SETPTS_FILTER)                 += vf_setpts.o
 OBJS-$(CONFIG_SLICIFY_FILTER)                += vf_slicify.o
 OBJS-$(CONFIG_TRANSPOSE_FILTER)              += vf_transpose.o
 OBJS-$(CONFIG_UNSHARP_FILTER)                += vf_unsharp.o
index bade1dd..8ba0b62 100644 (file)
@@ -57,6 +57,7 @@ void avfilter_register_all(void)
     REGISTER_FILTER (PIXELASPECT, pixelaspect, vf);
     REGISTER_FILTER (SCALE,       scale,       vf);
     REGISTER_FILTER (SETTB,       settb,       vf);
+    REGISTER_FILTER (SETPTS,      setpts,      vf);
     REGISTER_FILTER (SLICIFY,     slicify,     vf);
     REGISTER_FILTER (TRANSPOSE,   transpose,   vf);
     REGISTER_FILTER (UNSHARP,     unsharp,     vf);
index 5ce4641..e8146e0 100644 (file)
@@ -25,7 +25,7 @@
 #include "libavutil/avutil.h"
 
 #define LIBAVFILTER_VERSION_MAJOR  1
-#define LIBAVFILTER_VERSION_MINOR 53
+#define LIBAVFILTER_VERSION_MINOR 54
 #define LIBAVFILTER_VERSION_MICRO  0
 
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
diff --git a/libavfilter/vf_setpts.c b/libavfilter/vf_setpts.c
new file mode 100644 (file)
index 0000000..8ce7d6a
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2010 Stefano Sabatini
+ * Copyright (c) 2008 Victor Paesa
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * video presentation timestamp (PTS) modification filter
+ */
+
+/* #define DEBUG */
+
+#include "libavutil/eval.h"
+#include "avfilter.h"
+
+static const char *var_names[] = {
+    "E",           ///< Euler number
+    "INTERLACED",  ///< tell if the current frame is interlaced
+    "N",           ///< frame number (starting at zero)
+    "PHI",         ///< golden ratio
+    "PI",          ///< greek pi
+    "POS",         ///< original position in the file of the frame
+    "PREV_INPTS",  ///< previous  input PTS
+    "PREV_OUTPTS", ///< previous output PTS
+    "PTS",         ///< original pts in the file of the frame
+    "STARTPTS",   ///< PTS at start of movie
+    "TB",          ///< timebase
+    NULL
+};
+
+enum var_name {
+    VAR_E,
+    VAR_INTERLACED,
+    VAR_N,
+    VAR_PHI,
+    VAR_PI,
+    VAR_POS,
+    VAR_PREV_INPTS,
+    VAR_PREV_OUTPTS,
+    VAR_PTS,
+    VAR_STARTPTS,
+    VAR_TB,
+    VAR_VARS_NB
+};
+
+typedef struct {
+    AVExpr *expr;
+    double var_values[VAR_VARS_NB];
+} SetPTSContext;
+
+static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
+{
+    SetPTSContext *setpts = ctx->priv;
+    int ret;
+
+    if ((ret = av_parse_expr(&setpts->expr, args ? args : "PTS",
+                             var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
+        av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n", args);
+        return ret;
+    }
+
+    setpts->var_values[VAR_E          ] = M_E;
+    setpts->var_values[VAR_N          ] = 0.0;
+    setpts->var_values[VAR_PHI        ] = M_PHI;
+    setpts->var_values[VAR_PI         ] = M_PI;
+    setpts->var_values[VAR_PREV_INPTS ] = NAN;
+    setpts->var_values[VAR_PREV_OUTPTS] = NAN;
+    setpts->var_values[VAR_STARTPTS   ] = NAN;
+    return 0;
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+    SetPTSContext *setpts = inlink->dst->priv;
+
+    setpts->var_values[VAR_TB] = av_q2d(inlink->time_base);
+
+    av_log(inlink->src, AV_LOG_INFO, "TB:%f\n", setpts->var_values[VAR_TB]);
+    return 0;
+}
+
+#define D2TS(d)  (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d))
+#define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
+
+static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
+{
+    SetPTSContext *setpts = inlink->dst->priv;
+    double d;
+    AVFilterBufferRef *outpicref = avfilter_ref_buffer(inpicref, ~0);
+
+    if (isnan(setpts->var_values[VAR_STARTPTS]))
+        setpts->var_values[VAR_STARTPTS] = TS2D(inpicref->pts);
+
+    setpts->var_values[VAR_INTERLACED] = inpicref->video->interlaced;
+    setpts->var_values[VAR_PTS       ] = TS2D(inpicref->pts);
+    setpts->var_values[VAR_POS       ] = inpicref->pos == -1 ? NAN : inpicref->pos;
+
+    d = av_eval_expr(setpts->expr, setpts->var_values, NULL);
+    outpicref->pts = D2TS(d);
+
+#ifdef DEBUG
+    av_log(inlink->dst, AV_LOG_DEBUG,
+           "n:%"PRId64" interlaced:%d pos:%d pts:%"PRId64" t:%f -> pts:%"PRId64" t:%f\n",
+           (int64_t)setpts->var_values[VAR_N],
+           (int)setpts->var_values[VAR_INTERLACED],
+           (int)setpts->var_values[VAR_POS],
+           inpicref ->pts, inpicref ->pts * av_q2d(inlink->time_base),
+           outpicref->pts, outpicref->pts * av_q2d(inlink->time_base));
+#endif
+
+    setpts->var_values[VAR_N] += 1.0;
+    setpts->var_values[VAR_PREV_INPTS ] = TS2D(inpicref ->pts);
+    setpts->var_values[VAR_PREV_OUTPTS] = TS2D(outpicref->pts);
+    avfilter_start_frame(inlink->dst->outputs[0], outpicref);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+    SetPTSContext *setpts = ctx->priv;
+    av_free_expr(setpts->expr);
+    setpts->expr = NULL;
+}
+
+AVFilter avfilter_vf_setpts = {
+    .name      = "setpts",
+    .description = NULL_IF_CONFIG_SMALL("Set PTS for the output video frame."),
+    .init      = init,
+    .uninit    = uninit,
+
+    .priv_size = sizeof(SetPTSContext),
+
+    .inputs    = (AVFilterPad[]) {{ .name             = "default",
+                                    .type             = AVMEDIA_TYPE_VIDEO,
+                                    .get_video_buffer = avfilter_null_get_video_buffer,
+                                    .config_props     = config_input,
+                                    .start_frame      = start_frame, },
+                                  { .name = NULL }},
+    .outputs   = (AVFilterPad[]) {{ .name             = "default",
+                                    .type             = AVMEDIA_TYPE_VIDEO, },
+                                  { .name = NULL}},
+};