RB.
RB.

Reputation: 37212

Implementing RFC 5219 (MPA-Robust payload for RTP): How does one know they have read an entire ADU?

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

Answers (1)

RB.
RB.

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

Related Questions