How to get AVFoundation devices to have a consistent playback rate (1.0x) W/ FFMPEG on MacOS

Solution 1:

I've been struggling with this issue as well. It seems to be due to the stitching together of frames, meaning that dropped frames would give you a shorter video at the same rate (i.e. a faster video). I've found a solution that allows for a stable frame rate:

-framerate and -r are separate input options

If you take a look at this documentation page it explains that -r and -framerate are separate options, but generally you will want to use the input option -framerate.

-r as an input option works differently than -r as an output option. My understanding is that using -framerate as an input option tells the webcam capturing the footage what settings to use for the input stream but doesn't account for frame dropping or extra frames on the output stream.

Specifying the framerate of the output file

Instead, as mentioned in this wiki page, you can use the -r option as an output option to specify a constant frame rate stream if using .mp4 as your target format. However since you're using .mkv it will specify a FPS ceiling and allow lower FPS than the maximum specified.

Because your input is recording at roughly 60fps, then the following command would drop every other frame to give you a stable 30fps:

ffmpeg -framerate 59.940180 -f avfoundation -i "2:none" -r 30 output.mkv

Since you're actually looking to record at 60 frames per second, then raising the fps ceiling doesn't do much for you when writing to .mkv. Instead, another option would be to use an FPS filter that will duplicate frames if needed to reach the 60 fps you're looking for. An example command would be:

ffmpeg -framerate 59.940180 -f avfoundation -i "2:none" -filter:v fps=60 output.mkv

This would drop any frames above 30fps and duplicate any frames below that number to give you a stable framerate and (hopefully) a stable recording speed.

Extra Note

Something else that may not be important to your needs, but is worth considering is that the default functionality of your above command will also handle encoding your input stream before saving it to disk. This is highly CPU intensive for higher-end cameras, or for multi-cam setups. This could be part of the problem you are experiencing, unless you have a very beefy computer.

A solution here (which is what I currently do) is to copy the video stream to file without encoding, and then performing the encoding later. i.e.

ffmpeg -framerate 59.940180 -f avfoundation -i "2:none" -c:v copy -filter:v fps=60 output.mkv

The above command changes the video codec to just copy the stream instead of using an encoding algo. -c:v copy does this.

Then you can later encode the output with something like:

ffmpeg -i out.mkv -c:v libx264 -crf 0 -preset medium -tune film -pix_fmt yuv420p encoded.mkv

Notice that -c:v now specifies libx264. Hope this helps!