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

up vote 13 down vote accepted

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 '13 at 3:57
  • 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 at 18:37

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 '13 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 '13 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 '13 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) – Peter Cordes Dec 27 '14 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.) – Peter Cordes Dec 27 '14 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.

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:

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


# Prepare basic variables
IN_FILE="$1"
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.

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.