Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: Is it possible to stitch MP3 frames together? (Read 6240 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

Is it possible to stitch MP3 frames together?

I've read most posts on this subject, but still can't find out why I hear a click between each MP3 chunk...

I'm working with CBR, no bit reservoir, 192k bitrate, and 48k sample rate MP3 files.

CBR + 192k bitrate + 48k sample rate gives a clean 576 bytes per frame.

No bit reservoir is to make each frame independent.

The reason I want to stitch them is that I want to stream the MP3 (chunk by chunk).

Therefore I need to decode each chunk into PCM for playback.

When stitching the raw PCM data of the decoded MP3 together, I can hear a click/glitch/silence/something between each chunk on playback.

How can I stream MP3 perfectly without any click, considering my constraints (only CBR, no bit reservoir, etc)? Is it even possible?

Edit 1

This comment seems to imply that, even with the bit reservoir disabled, I can't simply stitch the MP3 chunks together?

Re: Is it possible to stitch MP3 frames together?

Reply #1
This comment seems to imply that, even with the bit reservoir disabled, I can't simply stitch the MP3 chunks together?
Correct. Other than the first frame in the stream, you can't fully decode any MP3 frame without information from the previous frame. You need to use a decoder that can handle partially decoding the MP3 as it arrives.

You don't need to disable the bit reservoir.

Re: Is it possible to stitch MP3 frames together?

Reply #2
Correct. Other than the first frame in the stream, you can't fully decode any MP3 frame without information from the previous frame. You need to use a decoder that can handle partially decoding the MP3 as it arrives.

You don't need to disable the bit reservoir.

I see.

1. I'm using FFMPEG as a decoder - doesn't it support partial chunks?
2. What about this part from LAME's FAQ? 👇

Quote
Two possible solutions:

1. Create mp3's with the --nores option in LAME,
(disabling the bit reservoir and reducing quality somewhat),
these mp3 files can be simply cut and pasted on frame boundaries.

The LAME documentation seem to imply that it's possible to stitch MP3 frames together so long as we disable the bit reservoir 🤔

Thanks for the help 🙏

Re: Is it possible to stitch MP3 frames together?

Reply #3
1. I'm using FFMPEG as a decoder - doesn't it support partial chunks?
It does. Unfortunately, I'm not familiar with the API, so I couldn't tell you what you might need to do differently to make it decode your MP3 correctly.

2. What about this part from LAME's FAQ?
That refers to cutting apart the MP3 file and stitching the frames together in a different order - or even stitching together frames from different files. You're not doing that, so you can use the bit reservoir.

Re: Is it possible to stitch MP3 frames together?

Reply #4
Quote
It does. Unfortunately, I'm not familiar with the API, so I couldn't tell you what you might need to do differently to make it decode your MP3 correctly.

Got it. In my particular case, I need to decode each chunk to PCM data, one chunk at a time, so that would never work, right? I believe what you mean when you say: "You need to use a decoder that can handle partially decoding the MP3 as it arrives.", is that the decoder would receive a stream of the MP3 data and thus be able to gather the right data from different frames (N, N+1, N+2, or whatever frame it needs) (which might not be available if solo chunks are provided to the decoder). I hope this makes sense 😅

Quote
That refers to cutting apart the MP3 file and stitching the frames together in a different order - or even stitching together frames from different files. You're not doing that, so you can use the bit reservoir.

Why would cutting apart an MP3 file and stitching the frames together in a different order be possible, but not in the right order? 😶 Sorry if I'm missing something obvious.

Re: Is it possible to stitch MP3 frames together?

Reply #5
In my particular case, I need to decode each chunk to PCM data, one chunk at a time, so that would never work, right?
It definitely works! Lots of streaming audio services already do it this way. I just don't know enough about ffmpeg to tell you how to make it work.

I believe what you mean when you say: "You need to use a decoder that can handle partially decoding the MP3 as it arrives.", is that the decoder would receive a stream of the MP3 data and thus be able to gather the right data from different frames (N, N+1, N+2, or whatever frame it needs) (which might not be available if solo chunks are provided to the decoder).
You're close. It's actually using earlier frames (N, N-1, N-2, etc.) so the decoder should have access to all of them even if you're only giving it one frame at a time.

Why would cutting apart an MP3 file and stitching the frames together in a different order be possible, but not in the right order?
With the bit reservoir disabled, both should be possible. With the bit reservoir enabled, you can only decode the frames in the right order.

Re: Is it possible to stitch MP3 frames together?

Reply #6
Quote
You're close. It's actually using earlier frames (N, N-1, N-2, etc.) so the decoder should have access to all of them even if you're only giving it one frame at a time.

But how can the decoder have access to all of the frames if I'm giving it one frame at a time? This assumes that the decoder keeps the previous frames in memory, right? So what I said about needing to feed a stream of data to FFMPEG seems to be true.

For example, if I executed a ffmpeg command on one chunk
Code: [Select]
ffmpeg -i chunk1.mp3 ... output1.wav
and then another command on another chunk
Code: [Select]
ffmpeg -i chunk2.mp3 ... output2.wav
ffmpeg doesn't keep the previous chunk in memory for the next command. This is basically what I'm doing right now. I believe what I would need to do instead is continuously stream the mp3 to FFMPEG. Otherwise, If I just decode the chunks independently, it won't work right?

Quote
With the bit reservoir disabled, both should be possible. With the bit reservoir enabled, you can only decode the frames in the right order.

I'm trying to understand what you mean here, because you also said

Quote
Correct. Other than the first frame in the stream, you can't fully decode any MP3 frame without information from the previous frame. You need to use a decoder that can handle partially decoding the MP3 as it arrives.

And this

Quote
That refers to cutting apart the MP3 file and stitching the frames together in a different order - or even stitching together frames from different files. You're not doing that, so you can use the bit reservoir.

So let me clarify this:  Is it possible to stitch MP3 frames together so long as we disable the bit reservoir (as seemed to be descibed in the LAME doc I pointed out earlier)? 🤔

Thanks again 🙏

Re: Is it possible to stitch MP3 frames together?

Reply #7
But how can the decoder have access to all of the frames if I'm giving it one frame at a time?
Either by feeding it frames through a pipe or by using the API directly. Right now, you're feeding it a separate file for each frame, so it doesn't know that they're supposed to all be part of a single stream.

Re: Is it possible to stitch MP3 frames together?

Reply #8
Either by feeding it frames through a pipe or by using the API directly. Right now, you're feeding it a separate file for each frame, so it doesn't know that they're supposed to all be part of a single stream.

Ah right! That's my issue 🤔

I have some limitations with the tech I'm using (FFMPEG WASM → FFMPEG for the browser), which doesn't seem to support streams.

This is why my question about being able to stitch MP3 frames together is important to me, since I can only make multiple independent calls to FFMPEG and then stitch the results together.

But from what I can intuit from our conversation here (as I said in my previous reply, I'm still a bit confused), even if I disable the bit reservoir (as an attempt to make each frame independent), the frames are not 100% independent (maybe because of the MDCT coefficients stuff?), thus I can't decode frames and stitch them together 🥹

Please let me know if I understand the issue correctly.

Re: Is it possible to stitch MP3 frames together?

Reply #9
I have some limitations with the tech I'm using (FFMPEG WASM → FFMPEG for the browser), which doesn't seem to support streams.
Can you use different tech? Like this, for example.

But from what I can intuit from our conversation here (as I said in my previous reply, I'm still a bit confused), even if I disable the bit reservoir (as an attempt to make each frame independent), the frames are not 100% independent (maybe because of the MDCT coefficients stuff?), thus I can't decode frames and stitch them together 🥹
That's correct.

Re: Is it possible to stitch MP3 frames together?

Reply #10
Quote
That's correct.

Thanks, everything makes a lot more sense now!

Quote
Can you use different tech? Like this, for example.

I can definitely use another tech, as long as it works in the browser. This seems like a great possible lib to use 😮

This is a lot lower level though, I think I will need a lot of experimentation to figure out how it works 😅

Do you have some pointers for some of the following questions?
- Do you have some evidence that this lib supports streams? In other words, does this lib support piping audio data? I've read the doc, but it's still unclear to me if it supports this. I'm asking because if you suggested this lib as an alternative, you might know if it supports streams.
- Where should I start exploring - I'm not so familiar with those low-level libs. Should I start exploring libavcodec → lame? Or libavformat → lame?

Re: Is it possible to stitch MP3 frames together?

Reply #11
Do you have some evidence that this lib supports streams? In other words, does this lib support piping audio data?
It does! You'll feed the decoder your downloaded MP3 frame using avcodec_send_packet() and then repeatedly call avcodec_receive_frame() to get decoded audio until the decoder tells you it needs the next MP3 frame. You can do this as you download the MP3 frames.

Where should I start exploring - I'm not so familiar with those low-level libs. Should I start exploring libavcodec → lame? Or libavformat → lame?
This example might be helpful. I think you can do everything with just libavcodec; there's no container for libavformat to demux.

Re: Is it possible to stitch MP3 frames together?

Reply #12
Do you have some evidence that this lib supports streams? In other words, does this lib support piping audio data?
It does! You'll feed the decoder your downloaded MP3 frame using avcodec_send_packet() and then repeatedly call avcodec_receive_frame() to get decoded audio until the decoder tells you it needs the next MP3 frame. You can do this as you download the MP3 frames.

Where should I start exploring - I'm not so familiar with those low-level libs. Should I start exploring libavcodec → lame? Or libavformat → lame?
This example might be helpful. I think you can do everything with just libavcodec; there's no container for libavformat to demux.

Bless you my friend 😁🙏

I will report back 😎

Re: Is it possible to stitch MP3 frames together?

Reply #13
Hello.

I believe the problem is in the difference between "sticking two frames together and decode them" versus "decoding one frame, then decode the other frame and then stick the result together".

An MP3 decoder has some inherent delays. In order to be sample rate accurate, compliant decoders try to cut the beginning (and end, if it does have length info in a lametag or similar).
Also, decoding individually the frames means that the decoder always start from a silence start, which would be an incorrect assumption. (gapless playback works because a compliant decoder has the lametag information of samples to skip)

In case of two frames created from a consecutive stream, the second frame would not need to skip the initial part because that part is already audio.

In other words. If your application can send the mp3 already concatenated to a decoder, rather than sending individually each frame as a separate audio, then you should be done.

Also, I am assuming that you actually don't have any additional frame of information, like a frame with lametag at the beginning. That frame would then be considered an audio frame is you stick it to a previous frame.

Re: Is it possible to stitch MP3 frames together?

Reply #14
Hello JAZ!

Quote
I believe the problem is in the difference between "sticking two frames together and decode them" versus "decoding one frame, then decode the other frame and then stick the result together".

I believe this is correct. The former works, but the latter doesn't 😁

Quote
Also, decoding individually the frames means that the decoder always start from a silence start, which would be an incorrect assumption. (gapless playback works because a compliant decoder has the lametag information of samples to skip)

That's interesting. I don't think I'm qualified to make a comment on this 😅 But thanks for the info, it might prove useful in the future.

Quote
In case of two frames created from a consecutive stream, the second frame would not need to skip the initial part because that part is already audio.

In other words. If your application can send the mp3 already concatenated to a decoder, rather than sending individually each frame as a separate audio, then you should be done.

Also, I am assuming that you actually don't have any additional frame of information, like a frame with lametag at the beginning. That frame would then be considered an audio frame is you stick it to a previous frame.

Right! I think this is why the solution proposed by Octocontrabass makes sense. I'm still in the process of doing my implementation, but I have hope that using a stream will solve my problem 🥹🤞

Re: Is it possible to stitch MP3 frames together?

Reply #15
@Octocontrabass Worked super well 😎 Thank you 🙏