Why does FFmpeg choose 10+20+20 ms instead of an even 16 ms for 60 fps GIF images?
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?
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.