Fast and slow-motion video with ffmpeg

by

Screen Shot 2012-04-20 at 2.13.55 PM

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:

Actual speed:

Sped up:

A slowed down clip of that trick shot:

12 Comments

  1. Thanks, you can use the following to do the same with mencoder.

    mencoder -ovc copy -oac copy -speed .5 icarian_games_1.mp4 -o slow.mp4

    I prefer your example with ffmepg for slow motion.

    ffmpeg -i 2.mov -vf setpts=2*PTS -an s2.mp4

  2. Another comment is that the above command caused the video to be re-encoded, and if I added “-vcodec copy”, then the speed didn’t change. Is it possible to create a slow motion video without reencoding?

    (I should also mention that I had to add “-r 30″ to the ffmpeg command line to get it to work at all.)

  3. I’m trying to “normalize” the playback speed of a video with a time/gps matrix… Hence, record a video on my car and then “play” it as if I was driving always at the same speed. From the gps/time matrix I can obtain speed variation rated but this means slight changes in PTS all along the run. Do you know if there is a way to automate PTS so that we can control the playback speed with a property file such as “from 1 to 5 sec -> 1x ; from 5 to 8 sec -> 1.2x”, etc?

    • I did something similar to that but logged my speed from my car’s diagnostic port. Ended up writing a little filter in C and piped the frames out of and back into ffmpeg. This pts way could be cleaner but I can’t think of how I’d do it.

      I did some quick experiments with GPS on my phone but the location tracking seems a bit … unreliable. Have you had much success?

  4. Hi!

    It’s possible to use this to accelerate te movie changing the framrate?
    For exemple if I have a movie in 23.9fps and I want to do it in 25fps its possible use this to do it?
    I tried to use -r 25 but this is not good for playing on tv’s because of the judder effect!

    Thank you!

  5. Thanks for the article. I am playing different speeds of H264 MP4 in browser (flowplayer) no problem, but slowing down my video clips using your technique causes some really nasty side-effects in windows media player.

  6. Thanks, i was searching to do this. It’s working, but i would like do some similar. when run your instruction ffmpeg drops many frames, how i have a 2fps video i just would like play in 8X speed, i mean 16fps, without drops. Do you know how do that?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>