How to change the framerate of a video without reencoding

74,121

Solution 1

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.

Solution 2

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.

Solution 3

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.

Solution 4

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.

Share:
74,121
EboMike
Author by

EboMike

Updated on September 18, 2022

Comments

  • EboMike
    EboMike over 1 year

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

  • EboMike
    EboMike over 10 years
    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.
  • thom
    thom over 10 years
    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.
  • EboMike
    EboMike over 10 years
    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.
  • thom
    thom over 10 years
    setpts is unneeded, it is only used to sync two different streams from different containers. I do not have a GoPro but try this: ffmpeg -r 30 -i SourceMovie.mp4 -r 30 -vcodec libx264 -fast -film -b 5000k -acodec libvo_aacenc -ab 128k -ac 2 -ar 48000 DestMovie.mp4
  • EboMike
    EboMike over 10 years
    That just returns "Option framerate not found" - I suppose the mp4 codec doesn't support taking a framerate as input since it reads that from the input file already. Omitting the first -r 30 just results in the movie being recoded at 30fps, which means it has the same length but only 30 frames a second, so it removes 3 out of 4 source frames (kind of the opposite of what I want).
  • thom
    thom over 10 years
    You were right and I was mistaken. setpts can indeed be used for slow motion by manipulating the timestamps. "avconv -i SourceMovie.mp4 -vf setpts=4.0*PTS -r 30 -vcodec libx264 -fast -film -b 5000k -acodec libvo_aacenc DestMovie.mp4" would theoretically give you higher quality. If your hardware is fast enough you could even increase the value for -b
  • EboMike
    EboMike over 10 years
    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).
  • Peter Cordes
    Peter Cordes over 9 years
    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
    Peter Cordes over 9 years
    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.)
  • diversenok
    diversenok over 6 years
    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.
  • peterling
    peterling over 4 years
    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.
  • Al Lelopath
    Al Lelopath over 3 years
    @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.