Reputation: 37212
I'm attempting to implement RFC 5219: A More Loss-Tolerant RTP Payload Format for MP3 Audio.
I understand that, for a given MP3 frame, you can identify where the corresponding ADU starts by parsing out the "main_data_begin" backpointer and reading from the "bit reservoir" (i.e. the audio data in the previous few frames).
However, I cannot understand how, for a given MP3 frame, you know when an ADU finishes?
For example, consider the following 2 MP3 frames:
Therefore, ADU1's length is
Frame1.Length - Frame1.HeaderLength - 20 bytes
But how can I know that? Am I able to generate ADU1 from Frame1, or must I read in Frame2 before I can determine that Frame1 is complete and generate ADU1?
Note that there is a sample algorithm in RFC 5219 Appendex A.1 which contains the following pseudo-code:
do
{
// read a frame
}
while (totalDataSizeBefore < newFrame.backpointer ||
totalDataSizeAfter < newFrame.aduDataSize);
but nowhere does it define "aduDataSize" or how it's calculated, so it's not super helpful...
The only other clue I have is a vague suggestion I can read the part_2_3_length from the Side Information and that will tell me how long the ADU is - however, I can't find a really effective source for how to actually parse the part_2_3_length - I just know it's a 12/24-bit structure which would give me a value far too high to be a frame-size.
Upvotes: 1
Views: 85
Reputation: 37212
Eventually we found the answer in the Live555 source code (specifically MP3Internals.cpp).
Basically, you need to read the part_2_3_lengths for each granule in each channel, and then maths them.
Roughly:
uint numBits = 0;
for (int channelIdx = 0; channelIdx < isMono ? 1 : 2; channelIdx ++)
{
for (int granuleIdx = 0; granuleIdx < 2; granuleIdx ++)
{
numBits += SideInfoGranules[channelIdx][granuleIdx].Part_2_3_Length;
}
}
// Now maths this number. I don't know where the magic constants 7 and 8 come from though.
var aduDataSize = (numBits + 7) / 8;
The parsing of the part_2_3_length is a bit too involved to explain here, but is well explained in the getSideInfo1
and getSideInfo2
methods of MP3Internals.cpp (for example, here);
Upvotes: 1