A recent consulting project involved computing the VMAF, SSIM, and PSNR scores of 30 fps 480p video encoded from a 60 fps 1080p source file. I’ve not performed measurements like this in the past and assumed that simply converting the 60 fps sources file to 30 fps via the “-r” option would convert from 60 fps to 30 fps and discard every other frame, which is what I needed. This assumption proved incorrect, and it cost me a morning to figure out a workaround. Here’s what I came up with.
By way of background, here’s MediaInfo on the source file:
Here’s what I tried first, a command that converts the file into a Y4M file at 1080p resolution.
Here’s what MediaInfo said about the file I created. The frame rate looked correct, but when I loaded the file into the Moscow University Video Quality Measurement Tool and compared it to the 480p files I had scaled to 1080p files, I noticed the scores were abnormally low.
A bit more analysis revealed that while FFmpeg had delivered the requested frame rate, it had done so by halving the frame rate and converting the one-minute file to two-minutes and preserving every frame. In fairness, that’s what my argument asked FFmpeg to do, though clearly not what I wanted it to do.
To make a long story short, in FFmpeg-speak, I didn’t want to change the frame rate, I wanted to slow the video down, which you do with the setpts video filter documented here. According to the FFmpeg documentation, “The filter works by changing the presentation timestamp (PTS) of each video frame. For example, if there are two successive frames shown at timestamps 1 and 2, and you want to speed up the video, those timestamps need to become 0.5 and 1, respectively. Thus, we have to multiply them by 0.5. Note that this method will drop frames to achieve the desired speed.”
This sounded exactly what I wanted, so I tried this argument.
This command kept the same speed but threw out every other frame which is what I wanted. As luck would have it, however, it threw out the wrong frame – I needed odd frames to compare to my encoded files, and this produced even frames. I fixed this with a simple seek command that advanced FFmpeg 1/60 of a second into the file before starting the conversion.
This created a file I could use to compare to the 30 fps 480p files that I scaled to 1080p Y4M files to perform the comparison.
Author’s Note: During the actual project, I created the 30 fps comparison file in two stages, first creating the 60 fps Y4M file via the first argument, then converting that to 30 fps and seeking to the right frame via the third argument (substituting the 60 fps Y4M file for the input file). While writing this note, I tried contracting the steps to the third argument which seemed to work just fine, though strangely, the MediaInfo file read the following.
If you run into problems with your conversion, try converting to Y4M first, then from 60 fps to 30 fps. This creates a file that MediaInfo describes as follows.
In both cases, the file worked perfectly in the Moscow State University tool.
These FFmpeg to the Rescue articles will appear in future additions of my book Learn to Produce FFmpeg in 30 Minutes or Less, now on the 2018 Edition. The book helps beginning and intermediate FFmpeg users produce high-quality, bandwidth-efficient files and encoding ladders as efficiently as possible.