Repository navigation
Reuse the first pass's stats when a retry re-encodes - #145
Merged
Merged
Conversation
This was referenced Nov 6, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #139.
When an encode lands over the target,
twopass_loop()re-encodes at a lower bitrate. Each retry used to run both passes from scratch in a new temp folder. The first pass only studies the video and writes stats, and a retry changes nothing but the bitrate, so it wrote the same stats again. Now a retry skips the first pass and runs the second pass with the stats from the first attempt.This only affects software codecs. Hardware encoders (
*_nvenc,*_videotoolbox) run a single pass already.Changes
twopass.py:TwoPass.run()takes two optional arguments.log_diris the folder for the stats and progress files (without one,run()makes and deletes its own temp folder as before, e.g. for--dry-run).reuse_first_passskips the first pass and prints "Reusing the first pass's stats". A pass's progress file is deleted before the pass starts, so a retry's progress bar doesn't briefly show the last attempt's progress.__main__.py:twopass_loop()creates oneTemporaryDirectoryfor all attempts and passesreuse_first_pass=Truefrom the second attempt on.EncodeJob.start_pass()counted a new attempt when a first or single pass started. A retry now starts with a second pass, so a second pass right after another second pass also counts as a new attempt. The retry's progress bar runs from 50% to 100%, since the first half is already done.README.md: a sentence in the codec notes about faster retries, with the numbers below.Checked
10 seconds of a 1080p60 Call of Duty clip. Each codec encoded at 6 MiB, then retried at 5.1 MiB twice: once reusing the first attempt's stats, and once from scratch.
The reused retries land about as close to the target as full re-encodes. With verbose logging, x265 logs
slice=P but 2pass stats say Band a B-frame warning on every plain two-pass encode, with or without this change, and a reused retry adds no new warnings.A CLI run at
-s 5.1with x264 went over on the first attempt (5.12 MB), reused the stats, landed at 5.02 MB, and left noff4d-temp folders behind.AV1 isn't tested: this machine's ffmpeg build doesn't include
libaom-av1. libaom's first-pass stats don't depend on the target bitrate either, so it should behave like VP9.Tests
test_twopass.py: withreuse_first_pass, only the second pass runs and it points at the first attempt's stats (-passlogfilefor x264 and VP9,stats=for x265). A caller'slog_diris used and not deleted. Hardware codecs are unchanged. A retry's progress file starts empty.test_main.py:twopass_loop()passesreuse_first_passasFalse, True, Trueacross three attempts with one shared stats folder, which is deleted afterward.EncodeJob.status()counts attempt 2 for a retry that starts with the second pass, and for hardware retries.