I'm trying to change the framerate of an MP4 video (it's a 120fps GoPro video, I want to play it back at 30fps for a slow-motion effect).

I'm using avconv for this:

avconv -i SourceMovie.mp4 -vf setpts=4.0*PTS -r 30 DestMovie.mp4

That technically works, but it reencodes the movie. In addition to being slow, it's obviously a quality issue. Technically there should be a way to just set the fps in the header of video, how can I change that? (Any tool other than avconv would work too.)

5 Answers 5


MP4Box can do it.

The command

MP4Box -add SourceMovie.mp4#video -raw 1 -new test

creates the files test and test_track1.h264. You can now create an mp4 file with whichever supported framerate you would like (30 in this example):

MP4Box -add test_track1.h264:fps=30 -new DestMovie.mp4

MP4Box is part of the gpac package, so make sure it's installed.

  • 6
    It's really not straightforward, but I got it - you need to do it in two steps. First extract the video stream separately as raw (MP4Box -add source.mp4#video -raw 1 -new test) and then save it as an MP4 again (MP4Box -add test_track1.h264:fps=30 -new dest.mp4). You can add an audio track too there (via #audio).
    – EboMike
    Nov 11, 2013 at 3:57
  • 2
    It is better to use -single option for the first command. MP4Box -single 1 -raw 1 SourceMovie.mp4 creates only one file SourceMovie_track1.h264 instead of two.
    – diversenok
    Feb 4, 2018 at 18:37
  • @diversenok: using the command MP4Box -single 1 -raw 1 myfile.mp4 I get 2 files: myfile_track1.aac and myfile_tracke1.mp4, no .h264 file. Nov 2, 2020 at 2:34

Changing framerate in the header of the video(container) has no effect on the videostream (or audiostream) itself. Reencoding is the only option.

Videostreams have timestamps and in most video's the frames are interdependent to each other due to interframe compression. Some players can speed up and slow down the video but not by embedded commands or something. No player can change the framerate on the fly when a containercommand asks to do so. The videofile will end up out of specification (i.e. not following the standards) and 99.9% of the players will refuse to comply to it. It is quite impossible to do what you want without recoding. Of course you can wait with recoding until the last step in your editing.

  • 1
    Thanks thom! Stupid question though - why? Does each frame have a timestamp that compels the player to enforce a certain playback speed? I want the exact same frames, I just want them played back at a different rate.
    – EboMike
    Nov 4, 2013 at 17:14
  • 2
    Hi Mike, no your question is not stupid, frankly the way you think is quite clever. i like your way of thinking. I added more info to my answer because it was too long to put this in the commentbox.
    – thom
    Nov 4, 2013 at 18:07
  • Thanks! That's quite informative. Now as for recoding - what's the best way to do that with something like avconv? I used the command line above, but that resulted in horrible quality - I could almost see every macroblock.
    – EboMike
    Nov 4, 2013 at 22:17
  • 1
    The timestamps in video streams are stored in the container, not the raw h.264 bitstream itself, I think. As long as you just want to change the timing, but not the order, of which frame is displayed when, you shouldn't need to transcode, just remux. (And if you do xcode, with faster hardware you'd use -preset slower or veryslow to get more quality at the SAME bitrate, instead of just throwing more bits at the problem. And use -crf 18 or something, not ABR) Dec 27, 2014 at 6:31
  • 1
    I can't figure out how to get ffmpeg to output a different framerate though. Looks like mkvmerge / mp4box are necessary, unless you can get ffmpeg to output a raw .264 bitstream, and then use the fps option to the h.264 demuxer (which -h full documents it having, since the bitstream doesn't have timing info, just ordering.) Dec 27, 2014 at 6:40

In the event that your major intent is to play it in slow motion, and not to keep the file as MP4, you can use MKVmerge GUI tool to remux it into a Matroska container which can easily change the framerate. Remuxing is much better than reencoding, because it only changes the metadata, and not the stream itself.

First you install the package

sudo apt-get install mkvtoolnix-gui

Then you start MKVmerge GUI. You'll be faced with a window like this

mkvmerge gui 1

Simply press add button and select your file or even just drag-n-drop the file into "Input files" area. At this point you should be able to select the video stream in your video. You can also delete other streams, since they will just get in the way anyhow.

After you've selected it you should see the bottom tabs becoming active:

enter image description here

Change to "Format specific actions"

enter image description here

You can see that there is a field "FPS", where you can input the value of frames per second. It looked like you were planning to slow things down four times, so about 7 frames per second would be your goal. You can also use "Stretch by" option.

After that you can just change the name of the output file (if you want) and press "Start muxing".

The program will run and you should have your file.

  • In the german gui v19 it is called: "Standarddauer/BPS: 7" (for ~4 times slow motion) and the other setting is: "Anzeigebreite/-höhe: 1280x720" (according to your video format) Just keep the orig. format. These fields are on the right side and greyed out. You have to select the video file in the lower window to make the settings changeable. On the bottom "Zieldatei" you can change the output. Then just press "Multiplexen starten" and thats it.
    – peterling
    Feb 16, 2020 at 19:53

I also wanted to lossless slow down of my 120 FPS movies to 30 FPS. I made script which does it by changing sound tempo and modifying FPS directly in MP4 container. Following tools are required:

  1. avconv to convert audio streams
  2. sondstretch to slow down audio tempo
  3. gpac to get MP4Box to change FPS

Script used for conversion is here:

# Lossless slow down from 120 to 30 FPS #
#                                       #
# Use:                                  #
#                                       #
#   slow.bash <mp4_file>                #
#                                       #
#                           #-= OSi =-# #

# Prepare basic variables
NAME=$(echo "${IN_FILE}" | sed 's/\.[^.]*//')

# Clean up before start
rm -f "${NAME}.ac3" "${NAME}.wav" "${NAME}_.wav" "${NAME}" "${NAME}_track1.h264" "${NAME}_slow.mp4"

# Slow down sound
avconv -i "${IN_FILE}" -vn -acodec pcm_s16le "${NAME}_.wav"
soundstretch "${NAME}_.wav" "${NAME}.wav" -tempo=-75
avconv -i "${NAME}.wav" -vn -codec:a ac3_fixed -b:a 448k "${NAME}.ac3"

# Change video frame rate and multiplex with slowed sound
MP4Box -add "${IN_FILE}#video" -raw 1 -new "${NAME}"
MP4Box -add "${NAME}_track1.h264:fps=30" -add "${NAME}.ac3" -new "${NAME}_slow.mp4"

# Clean up when we are done
rm -f "${NAME}.ac3" "${NAME}.wav" "${NAME}_.wav" "${NAME}" "${NAME}_track1.h264"

This script creates copy of MP4 with _slow postfix.


If you have a .mp4 file and you wish to change the rate at which video players render the frames without any recoding, you can do this by changing the 'Sample duration' value(s) in the stts atom. There are probably packages (MP4Box?) that can do this, but if you want to do it yourself it is very straightforward with either a hex editor (doesn't really scale) or very simple python code. Either way, there are three simple steps:

  1. Identify the 'Time scale' value in the mdhd atom. The mdhd atom is described in detail here: https://developer.apple.com/documentation/quicktime-file-format/media_header_atom. In a hex editor, searching for 'mdhd' will put you at the start of the 'Type' field in the mdhd atom. The Time scale is a four byte field that begins 16 bytes further on from the Type field start (i.e., skip 12 bytes after the end of the Type field).
  2. Compute the desired Duration by dividing Time scale by your desired playback fps: Convert the hex Time scale to int, divide by fps, take the floor, and then convert back to hex. e.g., if Time scale is 00 00 40 00, that converts to 16384. If you want playback to be at 10 fps, then floor(16384/10)=1638, which is 00 00 06 66 in hex.
  3. Now you are ready to set the frame duration in the stts atom, which is described here: https://developer.apple.com/documentation/quicktime-file-format/time-to-sample_atom. Searching for 'stts' will put you at the beginning of the 'Type' field in the stts atom. Eight bytes further on is the four byte 'Number of entries' field which tells you how many entries are in the 'Time-to-sample' table that immediately follows. Each entry in that table, which often has just one entry, consists of two 4 byte values: sample count and sample duration. Changing the 4 byte sample duration to the hex value computed in step 2 will give you the desired playback rate.

In python3, it might look like this:

    with open(filename, 'rb') as f:
        mp4bytes = f.read()
    pos_mdhd = mp4bytes.find(b'mdhd')
    if pos_mdhd > 0:
        time_scale = int.from_bytes(mp4bytes[pos_mdhd + 16:pos_mdhd + 20], 'big')
        new_duration = (time_scale//new_fps).to_bytes(4, 'big')
        pos_stts = mp4bytes.find(b'stts')
        if pos_stts > 0:
            num_entries = int.from_bytes(mp4bytes[pos_stts + 8:pos_stts + 12], 'big')
            with open(filename, 'rb+') as g:
                for i in range(num_entries):
                    g.seek(pos_stts + 16 + (i*8))

That's it, just plug in your desired filename and new_fps. This will rewrite ALL the frame durations to yield the desired playback fps. Note that it also overwrites the input file, so make a backup first.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .