[FFmpeg-devel] [PATCH 3/3] avfilter/vf_fps: add option to change way how frames are duplicated

Paul B Mahol onemda at gmail.com
Tue Oct 29 19:00:57 EET 2019


Default behaviour is unchanged, and that is always rounding down when
picking which frame to clone.

Signed-off-by: Paul B Mahol <onemda at gmail.com>
---
 doc/filters.texi     | 19 +++++++++++++++++++
 libavfilter/vf_fps.c | 23 ++++++++++++++++++++---
 2 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index 1e815bf940..6b5bf53c6d 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -10740,6 +10740,25 @@ The default is @code{round}.
 @item input
 Pick output frame rate from input if it is available. The default is disabled.
 Useful to change input to constant frame rate without needing to know input frame rate.
+
+ at item frames
+Frames picking rounding method when duplicating frames.
+
+Possible values are:
+ at table @option
+ at item zero
+round towards 0
+ at item inf
+round away from 0
+ at item down
+round towards -infinity
+ at item up
+round towards +infinity
+ at item near
+round to nearest
+ at end table
+The default is @code{down}.
+
 @end table
 
 Alternatively, the options can be specified as a flat string:
diff --git a/libavfilter/vf_fps.c b/libavfilter/vf_fps.c
index 993a6be1b9..3e6f9265af 100644
--- a/libavfilter/vf_fps.c
+++ b/libavfilter/vf_fps.c
@@ -49,6 +49,8 @@ typedef struct FPSContext {
 
     AVRational framerate;   ///< target framerate
     int rounding;           ///< AVRounding method for timestamps
+    int frames_rounding;    ///< AVRounding method for cloning frames
+
     int eof_action;         ///< action performed for last frame in FIFO
 
     /* Set during outlink configuration */
@@ -89,6 +91,7 @@ static const AVOption fps_options[] = {
         { "round", "round similar to other frames",  0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_ROUND }, 0, 0, V|F, "eof_action" },
         { "pass",  "pass through last frame",        0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_PASS  }, 0, 0, V|F, "eof_action" },
     { "input", "use input framerate if available", OFFSET(input), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, V|F },
+    { "frames", "set rounding method for frames", OFFSET(frames_rounding), AV_OPT_TYPE_INT, { .i64 = AV_ROUND_DOWN }, 0, 5, V|F, "round" },
     { NULL }
 };
 
@@ -252,13 +255,27 @@ static int write_frame(AVFilterContext *ctx, FPSContext *s, AVFilterLink *outlin
         *again = 1;
         return 0;
 
-    /* Output a copy of the first buffered frame */
+    /* Output a copy of the buffered frame depending on frames rounding */
     } else {
-        frame = av_frame_clone(s->frames[0]);
+        int index;
+
+        if (s->frames_count < 2) {
+            index = 0;
+        } else {
+            switch (s->frames_rounding) {
+            case AV_ROUND_ZERO:     index = (s->next_pts - s->frames[0]->pts) >= 0 ? 0 : 1; break;
+            case AV_ROUND_INF:      index = (s->next_pts - s->frames[0]->pts) <= 0 ? 0 : 1; break;
+            case AV_ROUND_DOWN:     index = 0; break;
+            case AV_ROUND_UP:       index = (s->next_pts - s->frames[0]->pts) != 0 ? 1 : 0; break;
+            case AV_ROUND_NEAR_INF: index = (s->next_pts - s->frames[0]->pts) > (s->frames[1]->pts - s->frames[0]->pts) / 2 ? 1 : 0; break;
+            }
+        }
+
+        frame = av_frame_clone(s->frames[index]);
         if (!frame)
             return AVERROR(ENOMEM);
         // Make sure Closed Captions will not be duplicated
-        av_frame_remove_side_data(s->frames[0], AV_FRAME_DATA_A53_CC);
+        av_frame_remove_side_data(s->frames[index], AV_FRAME_DATA_A53_CC);
         frame->pts = s->next_pts++;
 
         av_log(ctx, AV_LOG_DEBUG, "Writing frame with pts %"PRId64" to pts %"PRId64"\n",
-- 
2.17.1



More information about the ffmpeg-devel mailing list