69

I have a short 60 fps video which I'd like to turn into a GIF file. I run

ffmpeg -i foo.flv foo.gif

and it produces a GIF file. Great!

The only problem is that the motion in the produced GIF video is janky and uneven. If I use another tool, I can see that FFmpeg has created a video where the first frame is 10 ms long, the second 20 ms, the third 20 ms, and then it repeats like that: 10 ms, 20 ms, 20 ms. If I use another tool to smooth it out to an even 16 ms for each frame (without changing the frame contents), the result looks beautiful.

Why is FFmpeg doing this? How can I ask it to write a GIF file that requests an even 16 ms per frame instead, so that I don't need to use a second tool?

I have now seen this related question asking whether 60 fps GIF videos even exist, but it doesn't address the question of how to ask FFmpeg to change its behavior. Additionally, it raises a new question: if 16ms is not a time that GIF can represent, what is the other tool I'm using doing, and why does it work well?

  • 1
    but it doesn't address the question of how to ask ffmpeg to change its behavior. --> that's what my answer in that thread does. – Gyan Jul 15 at 13:24
  • 1
    @Gyan Interesting. I read your answer as describing how to get it to do what it appears to already be doing: getting 60fps by choosing 10ms, 20ms, 20ms. In particular, the chunk of code if(not(mod(N,3)),PREV_OUTPTS+1,PREV_OUTPTS+2) looks to me like just what you would want for generating that 1-2-2 pattern. Am I wrong? – Daniel Wagner Jul 15 at 13:29
  • Mine creates a 2-2-1 pattern. If you omit the filter, ffmpeg will make a uniform 2-1-2 pattern if the input is a constant frame-rate input, but it could lead to an irregular pattern in some run of frames if it's not. – Gyan Jul 15 at 13:39
  • @Gyan Okay. As described in the question, the theoretically optimal pattern turns out to be practically suboptimal (in part, perhaps, because viewers screw things up as described in Ilmari Karonen's comment below); so this question is about getting ffmpeg to produce a gif with a constant framerate, which your answer does not do. – Daniel Wagner Jul 15 at 13:47
  • Of course not, a 60 fps CFR GIF is not possible, since 100/6 seconds cannot be represented precisely. My answer starts, this is the basic format to emulate a rolling average of 60 fps – Gyan Jul 15 at 14:26
84

As discussed at Do 60 FPS GIF's actually exist? Or is the maximum 50 FPS?, the resolution of frame times in GIF is 10ms, so a nice even 16ms per frame is not possible. So the answers to the questions, in order, are:

Why is ffmpeg doing this?

Because 10+20+20 gets you 60fps on average, and is the most precise approximation with that property that can be represented within the constraints of the GIF format.

How can I ask it to write a gif that requests an even 16ms per frame instead, so that I don't need to use a second tool?

You can't, because the gif format can't represent that. But I've found that asking it to make a 50fps video -- which can be exactly represented in the GIF format -- produces nice smooth results. This can be done with:

ffmpeg -i foo.flv -vf fps=50 foo.gif

This uses nearest-neighbor temporal interpolation to choose which frame to transfer to the output.

If 16ms is not a time that gif can represent, what is the other tool I'm using doing, and why does it work well?

The other tool I was using was GIMP, and its choice is to round each frame to the nearest representable size, so it was silently changing my requested 16ms/frame to 20ms/frame. It probably works well because my poor human eyes can't tell that everything was happening just slightly too slowly to be correct; only that motions were happening smoothly instead of at unusually-spaced intervals.

  • 12
    A word or two about what gif format can represent and what the constrains of gif format really are would improve this answer. – Mołot Jul 15 at 8:59
  • 10
    Note that, for historical compatibility reasons, many browsers will treat GIF frame delays of less than 20 ms as if they were 100 ms instead (and some may even do this for any delay less than 60 ms!). So you should never go above 50 fps, and for maximum compatibility, keep your GIF animations below 100 / 6 = 16.67 fps. – Ilmari Karonen Jul 15 at 10:32
  • 1
    @Gyan That sounds like nearest-neighbor temporal interpolation to me! Glad to know the precise behavior; I'll update the answer to mention it. – Daniel Wagner Jul 15 at 13:48
  • 1
    @Gyan No, that's precisely what nearest-neighbor iterpolation is: en.wikipedia.org/wiki/Nearest-neighbor_interpolation – mbrig Jul 15 at 15:39
  • 1
    Something you may want to add to your answer: If you want to use a different frame interpolation algorithm then you can use the framerate (linear) or minterpolate (motion compensation, slow) filters. At least with a new enough ffmpeg. – derobert Jul 17 at 17:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.