Losslessly Changing Video Framerate

Posted

I’ve been taking a few timelapse videos recently and as an ammeter I’ve just been using the default phone camera apps. Google Camera defaults to “Auto” for the speedup, which keeps the resulting video between 15 and 30s no matter how long you record for (with minimum of 5x speed). It also offers explicit 5, 10, 30 and 120x speeds. The iPhone forgoes explicit options and only offers an auto mode with 20-40s output target and a 20x minimum speed.

Both of these apps have a limitation that they can only output 30 fps video. The seems like a missed opportunity since the faster than real time playback already tends to produce jumpy video. Getting 60 fps (or even 120 fps) makes a huge improvement to smoothness. The hardware can easily support these output framerates as the capture framerate will still be lower than regular speed videos.

My preferred approach is to record the video at “twice the duration” as I actually want, then to speed it up after the fact. Recording at a higher input framerate always gives you more flexibility as you can always speed it up later, and if you carefully pick your input framerate you can do this losslessly to avoid degrading the video quality.

For example, if I want to end up with a 1 minute 60 fps video covering 1 hour of real time. I need to record at 60s×60Hz÷1h60\u{s} \times 60\u{Hz} \div 1\u{h} which is 1 fps. Google Camera doesn’t show you the framerate directly, but you can easily convert the input speeds to framerates. Since it always expects to output 30 fps the calculation is just 30fps÷speed30\u{fps} \div \v{speed}, so to capture at 1 fps I need to select 30x speed.

To losslessly convert the video you can use ffmpeg bitstream filters.

ffmpeg
	-i input-video.mp4 # Input file.
	-c copy # Don't transcode, remain lossless.
	-r 60 # Output framerate, this is mostly informational for the whole-video metadata.
	-fps_mode vfr # Don't drop frames to match the expected framerate, just preserve all input frames.
	-bsf:v "setts=ts=PTS/2" # Update the presentation time to 1/2 the previous one (play twice as fast).
	output.mp4 # Output file.

This can easily be adjusted to other framerates by changing the -r and -bsf:v values.