vf_fps: add 'start_time' option
authorJustin Ruggles <justin.ruggles@gmail.com>
Thu, 15 Aug 2013 20:14:57 +0000 (16:14 -0400)
committerJustin Ruggles <justinr@vimeo.com>
Tue, 20 Aug 2013 18:10:02 +0000 (14:10 -0400)
This allows for dropping or duplication to match a particular start time.

doc/filters.texi
libavfilter/vf_fps.c

index 2ee5ad5..52971c7 100644 (file)
@@ -1241,6 +1241,14 @@ This filter accepts the following named parameters:
 @item fps
 Desired output framerate.
 
+@item start_time
+Assume the first PTS should be the given value, in seconds. This allows for
+padding/trimming at the start of stream. By default, no assumption is made
+about the first frame's expected PTS, so no padding or trimming is done.
+For example, this could be set to 0 to pad the beginning with duplicates of
+the first frame if a video stream starts after the audio stream or to trim any
+frames with a negative PTS.
+
 @end table
 
 @anchor{frei0r}
index 7f51752..4583c89 100644 (file)
@@ -40,6 +40,8 @@ typedef struct FPSContext {
     int64_t first_pts;      ///< pts of the first frame that arrived on this filter
     int64_t pts;            ///< pts of the first frame currently in the fifo
 
+    double start_time;      ///< pts, in seconds, of the expected first frame
+
     AVRational framerate;   ///< target framerate
     char *fps;              ///< a string describing target framerate
 
@@ -54,6 +56,7 @@ typedef struct FPSContext {
 #define V AV_OPT_FLAG_VIDEO_PARAM
 static const AVOption options[] = {
     { "fps", "A string describing desired output framerate", OFFSET(fps), AV_OPT_TYPE_STRING, { .str = "25" }, .flags = V },
+    { "start_time", "Assume the first PTS should be this value.", OFFSET(start_time), AV_OPT_TYPE_DOUBLE, { .dbl = AV_NOPTS_VALUE}, INT64_MIN, INT64_MAX, V },
     { NULL },
 };
 
@@ -78,6 +81,7 @@ static av_cold int init(AVFilterContext *ctx)
         return AVERROR(ENOMEM);
 
     s->pts          = AV_NOPTS_VALUE;
+    s->first_pts    = AV_NOPTS_VALUE;
 
     av_log(ctx, AV_LOG_VERBOSE, "fps=%d/%d\n", s->framerate.num, s->framerate.den);
     return 0;
@@ -177,7 +181,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
             if (ret < 0)
                 return ret;
 
-            s->first_pts = s->pts = buf->pts;
+            if (s->start_time != AV_NOPTS_VALUE) {
+                double first_pts = s->start_time * AV_TIME_BASE;
+                first_pts = FFMIN(FFMAX(first_pts, INT64_MIN), INT64_MAX);
+                s->first_pts = s->pts = av_rescale_q(first_pts, AV_TIME_BASE_Q,
+                                                     inlink->time_base);
+                av_log(ctx, AV_LOG_VERBOSE, "Set first pts to (in:%"PRId64" out:%"PRId64")\n",
+                       s->first_pts, av_rescale_q(first_pts, AV_TIME_BASE_Q,
+                                                  outlink->time_base));
+            } else {
+                s->first_pts = s->pts = buf->pts;
+            }
         } else {
             av_log(ctx, AV_LOG_WARNING, "Discarding initial frame(s) with no "
                    "timestamp.\n");