Feat/temporal vbr - #205
Merged
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #205 +/- ##
==========================================
+ Coverage 93.08% 93.09% +0.01%
==========================================
Files 58 58
Lines 10366 10389 +23
==========================================
+ Hits 9649 9672 +23
Misses 505 505
Partials 212 212
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
FrantaBOT
approved these changes
Aug 13, 2026
thomas-vilte
force-pushed
the
feat/temporal-vbr
branch
from
August 13, 2026 16:45
8e8ac9c to
356b9aa
Compare
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.
Description
This is the last missing term from
compute_vbr, and it is fully portable.libopus compares the frame's spectral level against a running average and spends more bits on frames that stand out (
celt_encoder.c):It then applies the result by scaling the target:
The Q-domain shifts in both blocks are identities in the float build, so the calculation is effectively in direct log2 units and the factor becomes:
amount naturally goes to zero as the bitrate approaches 96 kb/s. Once there are enough bits available, shifting bits between frames based on their spectral level is no longer worth paying for.
I verified the port by instrumenting both implementations on the same clip: frame_avg, spec_avg, and temporal_vbr match frame by frame to the fifth or sixth decimal place. Over 3000 frames, the average temporal_vbr is 0.0634 in pion vs 0.0629 in libopus.
Measurement
Packet size and round-trip SNR in VBR over 3000 frames of music:
The bit usage barely changes (+0.07 and +0.22 bytes per frame), while SNR improves by +0.127 dB at 24 kb/s and +0.102 dB at 48 kb/s.
That's exactly what this term is supposed to do: it doesn't really ask for more bits, it moves them toward the frames that can make better use of them.
At 96 kb/s it has essentially no effect, as expected since the factor is nearly zero there.
CBR is unchanged: 15.0721 dB at 96 kb/s, identical to before.
VBR status after this change
pion is now spending between 1% and 2.4% fewer bytes than libopus and scores between 0.08 and 0.13 dB lower, roughly in proportion to the difference in bitrate.
At this point, the only remaining compute_vbr term is the tonality boost, which requires analysis.c. In this particular reference configuration it does not actually apply either: analysis->valid is 0, confirmed through instrumentation.
Reference issue
Part of #34.