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

Submitted by Paul B Mahol on Oct. 29, 2019, 5 p.m.

Details

Message ID 20191029170057.6116-3-onemda@gmail.com
State New
Headers show

Commit Message

Paul B Mahol Oct. 29, 2019, 5 p.m.
Default behaviour is unchanged, and that is always rounding down when
picking which frame to clone.

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

Comments

Moritz Barsnick Oct. 30, 2019, 9:05 a.m.
On Tue, Oct 29, 2019 at 18:00:57 +0100, Paul B Mahol wrote:
>      { "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 }

You forgot to add the corresponding option flags here.

Moritz
Paul B Mahol Oct. 30, 2019, 9:18 a.m.
On 10/30/19, Moritz Barsnick <barsnick@gmx.net> wrote:
> On Tue, Oct 29, 2019 at 18:00:57 +0100, Paul B Mahol wrote:
>>      { "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 }
>
> You forgot to add the corresponding option flags here.

No I have not. Today is good day for you because you will learn that
that options values will be used from previous occurrence. Otherwise
both options would get duplicated values listed.

>
> Moritz
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Moritz Barsnick Oct. 30, 2019, 9:38 a.m.
On Wed, Oct 30, 2019 at 10:18:50 +0100, Paul B Mahol wrote:
> > You forgot to add the corresponding option flags here.
>
> No I have not. Today is good day for you because you will learn that
> that options values will be used from previous occurrence. Otherwise
> both options would get duplicated values listed.

Thanks! Lesson learned!

Moritz

Patch hide | download patch | download mbox

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.
+
+@item frames
+Frames picking rounding method when duplicating frames.
+
+Possible values are:
+@table @option
+@item zero
+round towards 0
+@item inf
+round away from 0
+@item down
+round towards -infinity
+@item up
+round towards +infinity
+@item near
+round to nearest
+@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",