What is the best method for automating two-pass encoding in FFmpeg similar to one-pass CRF 22?

I typically use ffmpeg for converting movies to 720p with a one-pass CRF 22 and a max rate of 1400k, aiming to achieve the smallest file size while retaining good quality. My usual parameters are:

c:v libx264 -vf format=yuv420p,scale=1280:-2 -crf 22 -maxrate 1400k -bufsize 7000k

Through extensive encoding, I’ve observed that factors like black bars, color themes, and the frequency of high-motion scenes significantly impact the bitrate. The CRF 22 setting ensures consistent quality across all scenes, leading to some scenes hitting the 1400k max bitrate while others linger around 800k. Consequently, the average bitrate for the same movie often settles around 1100k. In such cases, I re-encode the movie with a lower maxrate (like 1100k) to achieve similar quality but at a reduced average rate of about 1000k.

Given this experience, I’m curious if there’s an automated two-pass method that could yield similar results. For instance, is it possible to run the first pass at CRF 22 and then adjust the second pass to target the average bitrate from the first pass? This approach would ideally lower the quality in those higher bitrate ranges from the first pass.

1 Like

Yes, FFmpeg’s two-pass encoding can help you achieve comparable quality and size efficiency by leveraging the average bitrate determined in the first pass. The two-pass method initially analyzes your video in the first pass, gathering detailed information about its complexity. This data is then used in the second pass to allocate bitrate more effectively. Here’s the approach:

In the first pass, your command would be something like:

ffmpeg -i input.mp4 -c:v libx264 -vf format=yuv420p,scale=1280:-2 -crf 22 -pass 1 -f mp4 /dev/null

This generates a log file without creating an output file, with the CRF value guiding the encoder to maintain a consistent quality level.

For the second pass, you target an average bitrate based on the first pass’s data:

ffmpeg -i input.mp4 -c:v libx264 -vf format=yuv420p,scale=1280:-2 -crf 22 -pass 2 -b:v average_bitrate -y output.mp4

Replace average_bitrate with your desired bitrate, perhaps inferred from the first pass.

Great, but how do I figure out the appropriate average_bitrate for the second pass?

You can determine the average bitrate by examining the log file generated after the first pass, or you can estimate based on your past experiences. For instance, if you’ve noticed that the average bitrate usually is around 1100k in your one-pass encodings, you might start by using that figure for the second pass.

Automating the extraction of the exact average bitrate can be somewhat intricate. You could create a script that parses the first pass’s log file to extract the average bitrate information and then input this into your second pass command. This, however, requires some scripting skills and an understanding of how FFmpeg’s log files are structured.

Lastly, the two-pass method should maintain a quality level similar to your one-pass setup, especially if you’re using the same CRF setting. Its primary advantage lies in its more efficient use of bitrate, potentially leading to better optimization of file size without a notable drop in quality. However, it’s always recommended to test and compare the results to ensure they meet your quality standards.