parsing - 实施 RFC 5219(RTP 的 MPA-Robust 有效负载):如何知道他们已经阅读了整个 ADU?
问题描述
我正在尝试实现RFC 5219: A More Loss-Tolerant RTP Payload Format for MP3 Audio。
我知道,对于给定的 MP3 帧,您可以通过解析“main_data_begin”反向指针并从“位存储库”(即前几帧中的音频数据)读取来识别相应 ADU 的开始位置。
但是,我无法理解,对于给定的 MP3 帧,您如何知道 ADU 何时完成?
例如,考虑以下 2 个 MP3 帧:
- Frame1 的 main_data_begin = 0。
- Frame2 有一个 main_data_begin = 20
因此,ADU1 的长度为
Frame1.Length - Frame1.HeaderLength - 20 bytes
但是我怎么知道呢?我是否能够从 Frame1 生成 ADU1,还是必须先读取 Frame2,然后才能确定 Frame1 已完成并生成 ADU1?
请注意,RFC 5219 附录 A.1中有一个示例算法,其中包含以下伪代码:
do
{
// read a frame
}
while (totalDataSizeBefore < newFrame.backpointer ||
totalDataSizeAfter < newFrame.aduDataSize);
但它没有定义“aduDataSize”或它的计算方式,所以它不是很有帮助......
我唯一的其他线索是一个模糊的建议,我可以从辅助信息中读取 part_2_3_length,这将告诉我 ADU 有多长 - 但是,我找不到真正有效的来源来实际解析 part_2_3_length - 我只知道它是一个 12/24 位结构,它会给我一个太高而无法成为帧大小的值。
解决方案
最终我们在 Live555 源代码(特别是 MP3Internals.cpp)中找到了答案。
基本上,您需要阅读每个通道中每个颗粒的 part_2_3_lengths,然后计算它们。
大致:
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_length的解析在这里解释有点繁琐,但是在MP3Internals.cpp的getSideInfo1
andgetSideInfo2
方法中有很好的解释(例如,这里);
推荐阅读
- python - 从每个象限获取最近点的快速方法
- python - python sagemath - 随机选择修改作为输入传递的列表
- php - 如何使用laravell api在android应用程序中将登录从电子邮件更改为手机号码?
- uefi - 从 efi 应用程序返回值到 efi shell
- iphone - 如何在从相机/图库中选择图像后将图像从一个屏幕传递到另一个屏幕并自动显示在第二个屏幕中作为导航到第二个屏幕
- .net - 获取来自 AWS IOT CORE 到 AWS Lambda .Net Core 的 MQTT 主题名称
- mysql - 为什么附加连接会使我的查询减慢 +10 秒?
- events - e.which 在 VSCode 中已弃用,在 html Web 组件中使用 auxclick
- firebase - Firebase/Flutter:编译器读取地图
作为地图 无法解决:/ - java - Java Selenium:profile.managed_auto_select_certificate_for_urls 选择证书的示例