【问题标题】:Parsing ID3V2 Frames in C在 C 中解析 ID3V2 帧
【发布时间】:2017-11-25 09:19:30
【问题描述】:

我一直在尝试通过解析 mp3 文件并检索每个帧的大小来检索 ID3V2 标记帧。到目前为止,我没有运气。

我已有效地将内存分配给缓冲区以帮助读取文件,并且已成功打印出标题版本,但在检索标题和帧大小时遇到​​了困难。对于标题帧大小,我得到 1347687723,虽然在十六进制编辑器中查看文件我看到 05 2B 19。

我的代码的两个 sn-ps:

typedef struct{ //typedef structure used to read tag information
char tagid[3];              //0-2  "ID3"
unsigned char tagversion;   //3    $04
unsigned char tagsubversion;//4     00
unsigned char flags;        //5-6   %abc0000
uint32_t size;              //7-10  4 * %0xxxxxxx
}ID3TAG;

if(buff){
    fseek(filename,0,SEEK_SET); 
    fread(&Tag, 1, sizeof(Tag),filename); 
    if(memcmp(Tag.tagid,"ID3", 3) == 0)
    {
        printf("ID3V2.%02x.%02x.%02x \nHeader Size:%lu\n",Tag.tagversion, 
    Tag.tagsubversion, Tag.flags ,Tag.size);    
    }

}

【问题讨论】:

  • 也许你需要一个打包的struct,可能有填充字节用于对齐uint32_t size。使用了 10 个字节的存储空间,但 MSVC 报告 struct 的大小为 12。一种安全的方法是将数据读入 unsigned char 的数组并从数组中取出值。

标签: c parsing bit-manipulation id3v2


【解决方案1】:

由于内存对齐,编译器在 flagssize 之间设置了 2 个字节的填充。如果您的结构直接放入内存中,则大小将位于地址 6(从结构的开头)。由于 4 字节大小的元素必须位于 4 的地址倍数,因此编译器会添加 2 个字节,以便 size 移动到最接近 4 地址的倍数,即这里的 8。所以当你阅读从您的文件中,size 包含字节 8-11。如果你尝试打印 *(&Tag.size - 2),你肯定会得到正确的结果。

要解决此问题,您可以逐个读取字段。

【讨论】:

  • 感谢您的回复。使用 *(&Tag.size-2) 打印 %lu 打印出 53691465,使用 %x 打印打印出 3334449。我对这些值仍然有些困惑。 05 2B 19 从十六进制到十进制是 338713,我假设这个值代表字节,因此它应该是大约 2709704 位。
  • 可能还有其他一些遗漏的参数。尝试一一阅读字段,并告诉我它是否有效。
【解决方案2】:

ID3v2 标头结构在所有 ID3v2 版本(ID3v2.0、ID3v2.3 和 ID3v2.4)中都是一致的。

它的大小存储为 big-endian synch-safe int32

Synchsafe 整数是 保持其最高位(位 7)为零的整数,形成七位 八个可用。因此一个 32 位同步安全整数可以存储 28 一些信息。

示例:
255 (%11111111) 编码为 16 位同步安全整数是 383 (%00000001 01111111)。

来源:http://id3.org/id3v2.4.0-structure § 6.2


下面是一个简单的、真实的 C# 实现,您可以轻松地适应 C

public int DecodeSynchSafeInt32(byte[] bytes)
{
    return                 
        bytes[0] * 0x200000 +   //2^21
        bytes[1] * 0x4000 +     //2^14
        bytes[2] * 0x80 +       //2^7
        bytes[3];
}

=> 使用您在十六进制编辑器上读取的值 (00 05 EB 19),实际标签大小应为 112025 字节。

【讨论】:

  • 否:ID3v2.2 使用 3 个字节的 24 位,v2.3 使用 4 个字节的 32 位,v2.4 使用 4 个字节的 28 位 - 见 id3.org/id3v2.3.0#ID3v2_frame_overviewid3.org/id3v2-00
  • @AmigoJack 您所描述的与 帧头 相关,而不是 ID3v2 头。从 OP 的代码来看,他正在尝试读取 ID3v2 标头
  • 是的,你是对的。 OP声明“标题和帧大小”,因此我想知道为什么缺少有关帧的信息。
【解决方案3】:

巧合的是,我也在开发 ID3V2 阅读器。该文档说该大小以四个 7 位字节编码。因此,您需要另一个步骤将字节数组转换为整数...我认为仅将这些字节作为 int 读取是行不通的,因为顶部有空位。

【讨论】:

  • 似乎是评论,而不是实际答案。不要使用答案来制作 cmets。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-10
  • 1970-01-01
  • 1970-01-01
  • 2015-08-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多