Repository navigation
Conversation
Owner
|
Support for stb_vorbis is being removed in a future version and I'm no longer doing maintenance on it. It's recommended you use the libvorbis custom decoder in |
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.
Base branch:
dev. The same lines are ondev-0.12, and the change applies to them unchanged.Summary
When a Vorbis file is opened through callbacks,
ma_stbvorbis_init_internal_decoder_push()reads it 4 KiB at a time, and after each read it callsstb_vorbis_open_pushdata()again. That function starts over from the beginning of the data each time. So the number of calls grows with the size of the headers, and so does the work per call, which makes opening take quadratic time.The file doesn't need to be unusual for this to matter. Comment headers hold embedded cover art, which can be a few MiB. With a 4 MiB comment,
ma_decoder_init()takes 17 seconds at-O2.ma_sound_init_from_file()goes through the same code, by way of the VFS. This is on the thread that opens the file, unless the sound is loaded asynchronously.ma_stbvorbis_init_file()andma_stbvorbis_init_memory()use stb_vorbis's pull API, so they aren't affected.The fix
Double the buffer instead of adding 4 KiB to it, so the number of calls is logarithmic and the total work is linear.
Two other changes are needed to make that safe:
MA_AT_ENDalong with data. Reads are now larger, so they're more likely to reach the end of the file. A callback may returnMA_AT_ENDwith the last bytes it read, and the old code treated that as a failure. That rarely mattered with 4 KiB reads, but with larger reads it would stop some files that open today from opening. Now those bytes are used, and only a read that returns nothing ends the loop.That last condition also covers a callback that returns 0 bytes and
MA_SUCCESSat the end of the file. Growing only when full would otherwise turn that into an infinite loop. It already didn't return in practice, since the old loop kept growing the buffer instead.The buffer can be up to twice the size of the headers while opening. For a 1 MiB comment, peak memory goes from 2068 KiB to 3072 KiB.
Reproduction
The program takes
data/48000-stereo.ogg, rewrites it with a comment of the given size, opens it through callbacks and decodes the first frames. Run it from the root of the repository.It has to be built as C99 or later, as
stb_vorbis.cisn't C89.Before, on 877ea4a:
After:
The hash is the same throughout, so the audio doesn't change.