Help - Search - Members - Calendar
Full Version: MP3 Sync Words
Hydrogenaudio Forums > Lossy Audio Compression > MP3 > MP3 - Tech
jonboy
I'm writting a little program to split mp3 files.

I found some info on the Internet about the format of each frame in an MP3 file.

What I've done so far is to search through the file and find bytes that contain FFFF.

I figured those were the start of each header (sync word).

Then I split the file at the start of a particular frame and continue until I reach the desired length.

The split file plays back fine in all of the MP3 players I have.

The problem is when I try to process (re-encode) the split file using LAME - I get an error:

Number of channels has changed in MP3 file - not supported
Sample frequency has changed in MP3 file - not supported

It seems that LAME wants to see something else at the begginning of the file so I added
the first couple hundred bytes from the beggining of the original file to the split file and
LAME was able to process it (although it did say resyncing).

Also, if I do fix headers in Foobar2k, that makes it work in LAME, but I can see that it's adding stuff to the beginning of the file also.

So either I'm not splitting at the right point or I need to add something to the beginning of the files to make them work with LAME.

Does anyone know what info LAME is looking for?

Thank you!

Jon
jonboy
QUOTE(benski @ Jul 30 2006, 19:15) *

Interesting, but a bit cryptic. blink.gif

I still don't see what the first 36 bytes are for in that table.

This can't be part of the MP3 spec - I don't see why LAME should crap out when re-encoding if my file is conforming to the spec. I suspect there is some history behind it that I don't know about...

So, what's the best way fix my problem?

Try to copy the first xxx bytes from the original file and insert it at the beginning of the each split?

Is there just a generic header type dealy that I can add to make it happy?

Thanks,

Jon

Omion
I can see no reason why LAME would care whether the XING/LAME tag (which is what that is) is attached to the beginning of the file.

I think your problem stems from the fact that you say you are searching for "FFFF", when in fact the vast majority of frames start with "FFFB". You can see the setup of the MP3 frame header on this page.

I think what's happening is LAME is locking on to the "FFFF" bytes as a frame header (when in fact it's not) then it complains when it sees the real frame header has different information.


[edit]
Here's some extra info which may be helpful:
  • The first 36 bytes in the page benski linked to are the MP3 header (4 bytes) and the side info (32 bytes) They actually mean things to an MP3 decoder, so the XING tag can't use them.
  • Note that, due to the wackyness of MP3s, most of the time frames carry some information about the following frame as well (this is generally referred to as the "bit reservoir"). This means that if you cut at frame boundaries, there is a good chance that the first frame in the second file depends on the last frame in the first file.
  • I would look very hard at SebastianG's pcutmp3 tool, as it is designed to work around the bizarre MP3 issues that plague most splitters.
jonboy
QUOTE
I can see no reason why LAME would care whether the XING/LAME tag (which is what that is) is attached to the beginning of the file.
I think your problem stems from the fact that you say you are searching for "FFFF", when in fact the vast majority of frames start with "FFFB".
I think you are right about the search string. It looks like I should be searching for "FFFB".
So, I just changed the code to look for "FFFB" but I'm still having the same problem with LAME:
"Sample frequency has changed in MP3 File - not supported"
QUOTE
I think what's happening is LAME is locking on to the "FFFF" bytes as a frame header (when in fact it's not) then it complains when it sees the real frame header has different information.
That makes sense, maybe I'm still not locating the correct frame header. It looks good in the hex editor, however. tongue.gif
I'll try a different MP3 and see if that makes any difference.
BTW, is it actually LAME giving the error or the decoder?
QUOTE
I would look very hard at SebastianG's pcutmp3 tool, as it is designed to work around the bizarre MP3 issues that plague most splitters.
That's very cool! Nice work SebastianG.
I don't need to be so fine grained, however. I would be happy splitting at the frame boundry. biggrin.gif

If anyone has has more hints on how to do this, I'm all ears...

Jon


Omion
QUOTE
So, I just changed the code to look for "FFFB" but I'm still having the same problem with LAME:
"Sample frequency has changed in MP3 File - not supported"

Hm. Then maybe something else is happening.

QUOTE
BTW, is it actually LAME giving the error or the decoder?

Well, how are you doing the decoding? You just stuck the file through LAME again, right? If so, then LAME is the decoder, as well as the encoder. But yes, it is the decoder giving that error.

Looking at the LAME sources, the error is given when some header has a different configuration than the rest of the file. My guess is still that somewhere, somehow, a header is getting mis-read.

I just did a test where I changed the frequency information on only the first header, and LAME came back with a whole bunch of the same "Error: sample frequency has changed in MP3 file - not supported" errors. So I'm sure this is still what's going on.


PS. Do you just get that error once, or does it keep coming up? If it only comes up once, then it's a possibility that there's an error in the original file. Transcode the original file through LAME and see if the same error's there.
benski
When you find a sync word, compute the size of the frame, and see if there's another frame sync that distance away.

You may be hitting upon false frame sync words, which confuses the LAME decoder, as the next real frame it hits doesn't have the same (bad) info that the first frame had.
Omion
That would be the most reliable way to do it, but I get the feeling that jonboy was trying to avoid actually parsing stuff.

@jonboy:
If you do end up parsing the header, the page I linked to in my first post tells how to extract the bitrate from the header. Then you need to figure out how many bytes that bitrate has per frame.

For 44100Hz files, the equation is:
bytes_per_frame = 160/49 * kbit_per_second

So a 128kbps frame has 417.959 bytes in it. This is approximated with the padding bit: an unpadded 128kbps frame therefore has 417 bytes in it. A padded 128kbps frame has 418 bytes.

Remember: you still have a chance to use pcutmp3! tongue.gif
jonboy
Oh, hey. I didn't realize there were replies since my last post; never got notified.

Anyway, decided to take another look at this since I had a little time today.

Well, it turns out that the particular mp3 file I was testing uses "FFF3" instead of "FFFB" to mark the headers.

Does this mean no checksum? Is this pretty standard?

I guess I'm going to have to get real bitty if I want to make this work for reals.

LAME can read my split file now and it seems to work although I see a message that says "Can't step back 89!" now.

What does that mean?

Jon
Omion
QUOTE(jonboy @ Aug 14 2006, 18:13) *

Well, it turns out that the particular mp3 file I was testing uses "FFF3" instead of "FFFB" to mark the headers.

Does this mean no checksum? Is this pretty standard?

Yeah. It means no checksum and it's actually MPEG2 (either 24000, 22050, or 16000 KHz)

The "can't step back 89" is an extremely standard response to cutting on frame boundaries. It's what I'd mentioned in my first post:
QUOTE
Note that, due to the wackyness of MP3s, most of the time frames carry some information about the following frame as well (this is generally referred to as the "bit reservoir"). This means that if you cut at frame boundaries, there is a good chance that the first frame in the second file depends on the last frame in the first file.

That just means that 89 bytes of the first frame are actually in the previous frame, which is now in a different file.
jonboy
QUOTE(Omion @ Aug 14 2006, 22:29) *
Yeah. It means no checksum and it's actually MPEG2 (either 24000, 22050, or 16000 KHz)

Ahhh...OK. Yes it is 22050. I didn't know it was MPEG2 encoded.

QUOTE(Omion @ Aug 14 2006, 22:29) *
That just means that 89 bytes of the first frame are actually in the previous frame, which is now in a different file.
OK. I guess this is the bit reservoir thingy. tongue.gif

Does this mean that I loose a fraction of a second off the beginning of the split?
If that's the case, I can probably live with it since these will mostly be voice audio files that I want to split.

However, I understand that I can specify no bit reservoir in lame.
Now I'm thinking I should convert the files using this option and then do the split.
That way, I'll be guaranteed to get my FFFB search string, too.

Sound like a plan?

Jon

Omion
QUOTE
Does this mean that I loose a fraction of a second off the beginning of the split?
If that's the case, I can probably live with it since these will mostly be voice audio files that I want to split.

Yeah, most programs will throw out the first frame of audio (usually around 26ms) if that happens.

QUOTE
However, I understand that I can specify no bit reservoir in lame.
Now I'm thinking I should convert the files using this option and then do the split.

That sounds good if you really want that last frame. However, keep in mind that it will increase the bitrate by about 20% for the same quality.
[shameless plug]
If you want to, you can use the mp3packer program (convienently written by me biggrin.gif ) after you split the files to undo the bitrate increase.
[/shameless plug]

QUOTE
That way, I'll be guaranteed to get my FFFB search string, too.

Well, the FFFB happens if you use an unprotected MP3 with samplerate of 48000, 44100, or 32000KHz. The bit reservoir has no effect on the sync word.
jonboy
QUOTE(Omion @ Aug 14 2006, 23:36) *
If you want to, you can use the mp3packer program (convienently written by me biggrin.gif )
Nice! But you wrote it in Perl. tongue.gif

Just kidding, I will take a look. It looks cool. (Now I know why you know so much about this stuff!)
QUOTE
Well, the FFFB happens if you use an unprotected MP3 with samplerate of 48000, 44100, or 32000KHz. The bit reservoir has no effect on the sync word.
Right, but I will use one of those sample rates so I should get a predicatable sync word.

Thanks!

Jon
jonboy
I have another question of the audio gods. smile.gif

Say I decide to play around with this bit reservoir dealy.

How would I figure out how many frames to go back (or forward)
to get to a "clean" starting frame?

How are the frames linked together?

Jon
Omion
Bleh. I had a very detailed response to this, but I restarted my computer before submitting... mad.gif

QUOTE
How would I figure out how many frames to go back (or forward)
to get to a "clean" starting frame?
Unfortunately, there's no one answer. It's possible that a file won't have any "clean" starting frames, or every frame might be OK. Any frame that doesn't use the bit reservoir is OK. Any others are not.

QUOTE
How are the frames linked together?
The bit reservoir is implemented as a 9-bit field in the side info (right after the header) that says how many bytes to go backwards in order to find the real start of the frame's data. If the bit reservoir is 0, then the frame's data starts at the beginning of the frame. If the bit reservoir is 1, the frame starts on the last byte of the previous frame. If it's very high, then it's quite possible that the frame's data is actually stored multiple frames away!

Here's how to check the bit reservoir:
CODE
11111111 111xxxxx xxxxxxxx xxxxxxxx AAAAAAAA Ayyyyyyy...
The "1" indicate the sync word. "x" is the other bits in the header. "A" represents the bit reservoir usage, "y" is other stuff. If all the "A" bits are 0, then it's safe to split right before the header.

Note that for MPEG2 and MPEG2.5 files, the field is only 8 bits. Also, if the frame uses CRC the field will be offset by 2 bytes relative to the header.


If you really wanted to make a program that can split on arbitrary frame boundaries, the only way to do it would be to encode without the bit reservoir. Even keeping track of bit reservoir usage and changing frame sizes won't work all the time.
jonboy
Thanks - that was helpful.

Sorry about your computer restart. I bet it was a good post. sad.gif

I probably don't even need to worry about the bit reservoir, it's mostly just curiosity at this point but it could come in handy later.

It seems to me that as long as I split on a real frame start then most players will be able to handle it regardless of the bit reservoir, right?

I mean, are there any known players that can't do this?

I read that the format was designed with streaming in mind so it seems like it should work.

I can only think of two problems if splitting on a frame that uses the bit reservoir:

1. Might loose a tiny bit of audio before playback will start.
2. Probably be a "glitch" if you tried to combine the files again.

Anything other problems you can think of?

Jon
Omion
QUOTE(jonboy @ Aug 17 2006, 20:23) *

I can only think of two problems if splitting on a frame that uses the bit reservoir:

1. Might loose a tiny bit of audio before playback will start.
2. Probably be a "glitch" if you tried to combine the files again.

Anything other problems you can think of?

Jon

Well, 2 is generally not a problem. If one file has all bytes before a certain place, and the other file has all the bytes after the same place, then rejoining them will result in the exact same file.
If you decide to rejoin the second file with another MP3, then you'll hear a glitch.

I've never heard anything about players breaking if the first frame doesn't make sense. I don't think such error-resiliance is required by the spec, but a program that dies on that error is certainly not very well put together.
Sebastian Mares
Just a side note: if you are looking for FF FB, it means that you will find only files that are (assuming you really found a valid synch word):

MPEG 1.0 Layer III (no MPEG 2.0 or 2.5, as well as Layer II or Layer I files will be found)
Protection bit must be set.

A MPEG 2.0 Layer II file with protection bit not set has synch words with values FF F4.
Omion
QUOTE(Sebastian Mares @ Aug 17 2006, 23:54) *
Protection bit must be set.

Another side note wink.gif : keep in mind that for FFFB, although the protection bit is set, that actually means that the frame is not protected. That really screwed me up for a few days while making mp3packer.

FFFB is by far the most common frame header, but as Sebastien says, if you have a non-MPEG1 file, or if it uses CRC, then syncing to FFFB will result in badness.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Invision Power Board © 2001-2008 Invision Power Services, Inc.