Fast and slow-motion video with ffmpeg
In my last installment we looked at all the reasons why editing video isn’t as easy as it should be. Let’s assume that we’ve cleared those hurdles, and now actually want to do some video editing from the command line. A not-uncommon video effect is fast- and slow-motion, sped-up or slowed-down video. Being common, you’d think it would be readily available in any video editing software, but you’d be wrong. Out of respect for all its other virtues, we’ll be using ffmpeg today.
Searching for “slow motion ffmpeg” or “speed up ffmpeg” turns up links like this blog and this forum that offer a method for getting video at different speeds, but it’s a terrible way to do it. The method involves breaking out each individual frame and then putting them all back together, dropping or duplicating frames as necessary to get the new framerate. This takes forever if you have a video of any length (you know, the sort’ve thing you might want to speed up), and can hurt the quality because you’re retranscoding.
Another wrong, but popular and plausible, method is simply changing the framerate. A faster or slower framerate should equate to faster or slower video playback, right? Yes and no. In certain cases, this might have the desired effect, but there are severe limits. Some standards, like NTSC, have fixed framerates, so changes aren’t going to work at all. Others, like H.264, have bit-rate limits so that the maximum framerate is dependent on the resolution of the video. Framerates outside of the common ranges are also handled differently by different video playback software, so the actual playback speed is dependent on that as well.
Two bad methods out of the way, the right way to change video speed using ffmpeg is by adjusting the “presentation time stamp” (PTS). This adjusts frames’ metadata related to how long each is displayed—exactly what you want. Adjusting it with ffmpeg is done via the setpts video filter like so:
ffmpeg -i input.mp4 -vf “setpts=(1/<speed>)*PTS” output.mp4
where <speed> is the multiplier you want (2x faster: speed=2, etc). ffmpeg’s video filters are a very powerful set of tools, but they’re not as well documented as they could be. In this case, the filter sets up the PTS variable for you which has the current PTS. In that way playback speed is adjusted relative to current speed, instead of in absolute terms. Because this is just metadata, not serious frame manipulation, the process is usually limited by the time necessary to write the output video to disk—fast!
As an example of ffmpeg’s sometimes lacking documentation, this information is right in the description of the setpts filter! However, if you didn’t already know that you wanted the PTS, you’d be unlikely to look there. The documentation in total is around thirty-thousand words, about the same length as Steinbeck’s Of Mice and Men, so unless you’ve got a keen interest and some time, you’re unlikely to find it by reading everything. I hope this post can help push the relevant info higher up in the search results.
Here’s the results:
A slowed down clip of that trick shot: