From 2a56f021aecef12e424e0bbcf6447a7a3079297d Mon Sep 17 00:00:00 2001
From: Thomas Mundt <loudmax@yahoo.de>
Date: Fri, 24 Mar 2017 02:26:24 +0100
Subject: [PATCH v2] avfilter/vf_fps: fix duration

Fix ticket #2674
This makes the fps filter better take account of the duration of the input file. Tested with examples from ticket 2674 and other files at various frame rates.

Signed-off-by: Thomas Mundt <loudmax@yahoo.de>
---
 libavfilter/vf_fps.c      | 43 +++++++++++++++++++++++++++++++++++++------
 tests/ref/fate/filter-fps |  6 ++++++
 2 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/libavfilter/vf_fps.c b/libavfilter/vf_fps.c
index 20ccd79..e71a70c 100644
--- a/libavfilter/vf_fps.c
+++ b/libavfilter/vf_fps.c
@@ -45,6 +45,7 @@ typedef struct FPSContext {
 
     /* timestamps in input timebase */
     int64_t first_pts;      ///< pts of the first frame that arrived on this filter
+    int64_t pkt_duration;   ///< packet duration of the current frame
 
     double start_time;      ///< pts, in seconds, of the expected first frame
 
@@ -56,6 +57,7 @@ typedef struct FPSContext {
     int frames_out;            ///< number of frames on output
     int dup;                   ///< number of frames duplicated
     int drop;                  ///< number of framed dropped
+    int frames_in_proc;        ///< number of input frames processed
 } FPSContext;
 
 #define OFFSET(x) offsetof(FPSContext, x)
@@ -126,24 +128,49 @@ static int request_frame(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     FPSContext        *s = ctx->priv;
+    AVFilterLink *inlink = ctx->inputs[0];
     int ret;
 
-    ret = ff_request_frame(ctx->inputs[0]);
+    ret = ff_request_frame(inlink);
 
     /* flush the fifo */
     if (ret == AVERROR_EOF && av_fifo_size(s->fifo)) {
         int i;
         for (i = 0; av_fifo_size(s->fifo); i++) {
+            int j, delta;
             AVFrame *buf;
 
             av_fifo_generic_read(s->fifo, &buf, sizeof(buf), NULL);
-            buf->pts = av_rescale_q(s->first_pts, ctx->inputs[0]->time_base,
-                                    outlink->time_base) + s->frames_out;
+            if (s->pkt_duration) {
+                delta = av_rescale_q_rnd(inlink->current_pts + s->pkt_duration -
+                                         s->first_pts, inlink->time_base,
+                                         outlink->time_base, s->rounding) -
+                                         s->frames_out;
+            } else if (s->frames_in_proc) {
+                delta = av_rescale_q_rnd((s->frames_in_proc + 1) *
+                                         (inlink->current_pts - s->first_pts) /
+                                         s->frames_in_proc, inlink->time_base,
+                                         outlink->time_base, s->rounding) -
+                                         s->frames_out;
+            } else
+                delta = 0;
+
+            if (delta < 1) {
+                s->drop++;
+                continue;
+            }
+            for (j = 0; j < delta; j++) {
+                AVFrame *out = av_frame_clone(buf);
+                out->pts = av_rescale_q(s->first_pts, inlink->time_base,
+                                        outlink->time_base) + s->frames_out;
 
-            if ((ret = ff_filter_frame(outlink, buf)) < 0)
-                return ret;
+                if ((ret = ff_filter_frame(outlink, out)) < 0)
+                    return ret;
 
-            s->frames_out++;
+                s->frames_out++;
+                if (j)
+                    s->dup++;
+            }
         }
         return 0;
     }
@@ -206,6 +233,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
         return write_to_fifo(s->fifo, buf);
     }
 
+    s->pkt_duration = av_frame_get_pkt_duration(buf);
+
     /* number of output frames */
     delta = av_rescale_q_rnd(buf->pts - s->first_pts, inlink->time_base,
                              outlink->time_base, s->rounding) - s->frames_out ;
@@ -223,6 +252,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
         return ret;
     }
 
+    s->frames_in_proc++;
+
     /* can output >= 1 frames */
     for (i = 0; i < delta; i++) {
         AVFrame *buf_out;
diff --git a/tests/ref/fate/filter-fps b/tests/ref/fate/filter-fps
index 55712cf..242fb04 100644
--- a/tests/ref/fate/filter-fps
+++ b/tests/ref/fate/filter-fps
@@ -85,3 +85,9 @@
 0,         79,         79,        1,    30576, 0xa2fcd06f
 0,         80,         80,        1,    30576, 0xa2fcd06f
 0,         81,         81,        1,    30576, 0xd4150aad
+0,         82,         82,        1,    30576, 0xd4150aad
+0,         83,         83,        1,    30576, 0xd4150aad
+0,         84,         84,        1,    30576, 0xd4150aad
+0,         85,         85,        1,    30576, 0xd4150aad
+0,         86,         86,        1,    30576, 0xd4150aad
+0,         87,         87,        1,    30576, 0xd4150aad
-- 
2.7.4.windows.1

