I have a series of JPEG images named 0000.jpg 0001.jpg 0002.jpg...
I used the following command to turn these into a slideshow video, each frame playing for 1 second.
ffmpeg -framerate 1 -i %04d.jpg -c:v libx264 -vf fps=1 -pix_fmt yuv420p out.mp4
This works fine except that the resulting video is 6x larger than what I get if I encode the exact same frames at normal framerate (e.g. 25 FPS)
I'm looking for a way to effectively get the same efficient encoding as when encoding 25fps but with each frame showing for 1 second.
H.264 is a video codec that is inter-coded i.e. frames rely on other frames in order to get decoded. What x264, a H.264 encoder, does, at a basic level, is observe the changes in the picture content between frames and then save only that difference.
In the CRF ratecontrol mode, which is what's used by default when no rate control mode is expressly specified (-b:v
, -crf
, -x264opts qp
), x264 is sensitive to framerate. When given an input at 25 fps, each frame is displayed for 40 milliseconds, so the viewer isn't that sensitive to image quality of each individual frame, so x264 compresses it quite a bit. But when that input is encoded at 1 fps, each output frame will be on display for a whole second, so x264 is much less aggressive with its compression.
The workaround is to encode at 25 fps and then remux at the lower fps.
#1
ffmpeg -framerate 25 -i %04d.jpg -c:v libx264 -pix_fmt yuv420p out.264
#2 Using mp4box*, part of GPAC, remux with the lower rate:
mp4box -add out.264:fps=1 -new out.mp4
*normally, this would be possible using ffmpeg, but it does not correctly remux H.264 raw streams with out-of-order frame storage i.e. those with B-frames.