eshaz/wasm-audio-decoders

mpg123-decoder only loading 15-25% of MP3 files

banjerluke opened this issue ยท 6 comments

All mp3 files that I decode with mpg123-decoder are consistently cut off about 15%-25% into the file. Files of the same length, bitrate, channel count, etc. seem to be decoded to the same point, but that point varies based on all those attributes (just not the contents of the file, it seems).

MP3 file permutations I've tried:

  • Short files (2s) and long files (over a minute)
  • Stereo, mono
  • CBR, VBR
  • 48kHz, 44.1kHz, 11025 Hz

Other things I've tried:

  • Both my fork (#6) and the unmodified library
  • Updating mpg123 submodule to 1.29.1

With DevTools, I verified that the full file is being passed to MPEGDecoder.decode - the byte length of the data argument length matches the file's size in bytes. Then it loops through each frame. Oddly, the first frame is always 0 samples. Then there are a series of 1152-sample decoded frames, then it ends. So it's looping through the entire source file, but only decoding up to ~1/4 of it.

I've hit a wall with trying to figure out what's going on here. Any ideas?

eshaz commented

I'm not sure what's going on here yet either. There might be a problem in how the data is being sent to mpg123. Right now it's sending the theoretical maximum frame size for MPEG audio to mpg123 on each iteration, but the data may actually have to be split up by the actual frame size instead. I'll try reproducing this myself and see what I can find.

I'm using this library to support icecast-metadata-player which works great by sending each MPEG frame individually to the decoder. I haven't tried this yet with a full Uint8Array of data from a file.

The first frame being 0 samples is probably ok. MPEG actually maintains state across multiple frames in what's called the bitreservoir. When the decoder is processing the frames, it's also maintaining this state and depending on the file and implementation of mpg123, it may take a few frames before outputting audio. At the end of the decoding process, all the expected decoded audio is supposed to be there.

Thanks for looking into it. I'll be curious to know if you run into the same issue or not.

It does seem like it wouldn't be necessary to decode actual frames, based on perusing the mpg123 API docs and seeing that you're using mpg123_decode as opposed to mpg123_decode_frame. That would be quite a pain for VBR files with varying frame sizes too.

And in perusing the mpg123 source it looks like mpg123_read, which I think is meant to be called repeatedly after opening a file, just calls mpg123_decode with a few default parameters, which supports the idea that frames don't matter here. (The mpg123_decode source also gives me that feeling, although I feel less qualified to interpret that code.)

The latest update with the Web Worker implementation is fantastic! I absolutely love the API you came up with; so elegant and ergonomic.

Still getting this issue with MP3 files, unfortunately, and it looks like I'm going to have to get WASM MP3 decoding working now instead of Opus, so it's rather important that I find a solution to this.

Did you happen to have a chance to give it a try yourself? Happy to help investigate however I can.

eshaz commented

Thanks for the compliment on the Web Worker implementation!

I just pushed a fix that should resolve this. Would you be able to download / install this latest version and give it a try? If it doesn't work, please reopen the issue and we can continue working through it.

What appeared to be happening was that mpg123 only returns the first frame that is found each time mpg123_decode() is called with some data. I didn't spend too much time verifying the cause in mpg123's source, but I'm pretty sure that was the problem. In this case, more than one frame's worth of data was being sent to mpg123_decode() since it was being split by max theoretical frame length. Changing the decode() function to split on the min theoretical frame length fixed the problem for me.

Yup, the entire file is being decoded now. Fantastic! ๐ŸŽ‰

I did notice a curious bug with invalid sampleRate values but I'll put it in a new issue... and it doesn't affect me, so personally I couldn't be happier! Where's your tip jar? ๐Ÿ˜ƒ

eshaz commented

Awesome and great to hear! There's no tip jar, at least not yet ;)