Fast and slow-motion video with ffmpeg

by

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:

20 Comments

  1. Zach on said:

    Hi I got some sort of error opening a filter: https://s24.postimg.org/9nhx8sos5/Capture.png

    Anyone care to comment on what this means and what it’s trying to tell me? Apparently others did it perfectly fine, but for me I just get hit with this error instead….

  2. Fabrizio on said:

    Hi, I would change the frame rate with PTS of a portion of a video.
    Do you know how?

  3. abc on said:

    Sadly, there is apparently NO way to automatically adjust the frame rate alongside the pts. So if you have a bunch of videos, with 25 different frame rates depending on the video, you have to manually look it up and type it in every time. You can do 0.5*PTS but you cannot do -r 0.5*FRAME_RATE (or some other variable – it is not documented)

  4. Pingback: timelapse aka speeding up with ffmpeg | Nova deViator

  5. Janis on said:

    I used it like this:
    ffmpeg -i source.mp4 -filter:v “setpts=0.05*PTS” fast.mp4
    The audio is synchronised all right, but the video length is displayed incorrectly in players: they show 30 min (of the original video) instead of 1.5 min (of the sped up video). It’s the same for WMP, VLC (where it breaks seeking to a specific time: e.g. if I click to the half of the video, it tries to seek to the 15th minute, but unsuccessfully, of course), and also on Youtube’s video list page, although when I open the video and it starts to play, the timer shows the correct 1.5 min length.

    • G on said:

      Same thing here, would be nice if you could provide a solution to that.

  6. Lindylex on said:

    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

    • Dinesh on said:

      Thankx bro this helped me solve that problem

    • Marcos Regis on said:

      Thank you for your comment. I tried several ways to turn a video of a sunset 13 minutes in a 1 minute (Time Lapse / Fast Motion) and finally found how to make using the IMencoder that comes along with the SUPER eRightSoft. I used the same mencoder command line only changing the multiplier of .5 to 13.

      IMEncoder.exe -ovc copy -oac copy -speed .5 13minutes_sunset.mp4 -o timelapse_sunset.mp4

  7. Dan on said:

    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.)

  8. Dan on said:

    When I use ffmpeg to convert a video to slow motion, the audio is kept at the same speed. Any suggestion for how to fix this?

  9. Angelo on said:

    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?

    • FluffyMcDeath on said:

      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?

  10. alex on said:

    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!

    • Andrew
      Andrew on said:

      This doesn’t change the framerate, just the frame display time.

  11. roger on said:

    now if it could just infer the frames between the existing frames…

  12. Andy Harrison on said:

    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.

  13. Giancarlo Colasante on said:

    I answer my question,
    ffmpeg -i Input.mp4 -r 16 -vf setpts=0.125*PTS -an Output.mp4
    Thank you

  14. Giancarlo Colasante on said:

    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?

  15. Alex on said:

    Brilliant! Big help, thanks :D

Leave a Reply

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