代码之家  ›  专栏  ›  技术社区  ›  RB.

实现RFC 5219(RTP的MPA鲁棒有效载荷):如何知道他们已经读取了整个ADU?

  •  1
  • RB.  · 技术社区  · 6 年前

    我正试图实现 RFC 5219: A More Loss-Tolerant RTP Payload Format for MP3 Audio .

    我知道,对于给定的MP3帧,您可以通过解析出“main_data_begin”反向指针并从“bit repositor”(即前几帧中的音频数据)读取来识别相应的ADU从何处开始。

    然而,我不明白,对于给定的MP3帧,你怎么知道ADU什么时候结束?

    例如,考虑以下2个MP3帧:

    • Frame1有一个main_data_begin=0。
    • Frame2的主数据开始=20

    因此,ADU1的长度为

    Frame1.Length - Frame1.HeaderLength - 20 bytes
    

    但我怎么知道?我是否能够从Frame1生成ADU1,或者我必须先阅读Frame2才能确定Frame1是否完整并生成ADU1?

    请注意,中有一个示例算法 RFC 5219 Appendex A.1 其中包含以下伪代码:

    do
    {
         // read a frame
    }
    while (totalDataSizeBefore < newFrame.backpointer ||
           totalDataSizeAfter < newFrame.aduDataSize);
    

    但它并没有定义“aduDataSize”或它的计算方式,所以它并没有太大的帮助。。。

    我唯一的另一个线索是一个模糊的建议,我可以从侧边信息中读取part_2_3_长度,这将告诉我ADU的长度——然而,我找不到一个真正有效的来源来解析part_2_3_长度——我只知道这是一个12/24位的结构,它会给我一个太高的值,无法作为帧大小。

    1 回复  |  直到 3 年前
        1
  •  1
  •   RB.    6 年前

    最终,我们在Live555源代码(特别是MP3Internals.cpp)中找到了答案。

    基本上,你需要读取每个通道中每个颗粒的部分长度,然后计算它们。

    大致上:

    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;
    

    这里对part_2_3_长度的解析有点过于复杂,无法解释,但是在 getSideInfo1 getSideInfo2 MP3内部的方法。cpp(例如, here );