二进制读取mp3文件的ID3标签

弗雷德里克

我正在尝试读取c ++中的mp3文件并显示该文件包含的id3信息。我遇到的问题是,当我读取帧头时,它所容纳的内容大小错误。而不是给我10字节的整数,而是给我167772160字节。http://id3.org/id3v2.3.0#ID3v2_frame_overview

struct Header {
   char tag[3];
   char ver;
   char rev;
   char flags;
   uint8_t hSize[4];
};

struct ContentFrame 
{
   char id[4];
   uint32_t contentSize;
   char flags[2];
};

int ID3_sync_safe_to_int(uint8_t* sync_safe)
{
   uint32_t byte0 = sync_safe[0];
   uint32_t byte1 = sync_safe[1];
   uint32_t byte2 = sync_safe[2];
   uint32_t byte3 = sync_safe[3];

   return byte0 << 21 | byte1 << 14 | byte2 << 7 | byte3;
}

const int FRAMESIZE = 10;

上面的代码用于将二进制数据转换为ASCCI数据。主要内部

Header header;
ContentFrame contentFrame;

ifstream file(argv[1], fstream::binary);
//Read header 
file.read((char*)&header, FRAMESIZE);

//This will print out 699 which is the correct filesize
cout << "Size: " << ID3_sync_safe_to_int(header.hSize) << endl << endl;

//Read frame header
file.read((char*)&contentFrame, FRAMESIZE);
//This should print out the frame size. 
cout << "Frame size: " << int(contentFrame.contentSize) << endl;

我已经在Perl中为此任务编写了一个程序,并且运行良好,其中使用了unpack,例如:

my($tag, $ver, $rev, $flags, $size) = unpack("Z3 C C C N"), "header");
my($frameID, $FrameContentSize, $frameFlags) = unpack("Z4 N C2", "content");

也可以使用sync_safe_to_int来正确设置标头的大小,但是对于竞争大小,它仅用于打印任何转换 N以“网络”(大端)顺序的无符号长(32位)。
C一个无符号的char(八位位组)值。
ZA以null终止的(ASCIZ)字符串,将以null填充。

我程序的输出:
标头内容
标签:ID3
版本:3版本
:0
标志:0
大小:699

错误输出!框架内容
ID:TPE1
大小:167772160
标志:

从Perl正确输出!帧内容
ID:TPE1
大小:10
标志:0

丹尼

contentFrame.contentSize定义为uint32_t,但打印为(signed)int

另外,如文档所述,多字节数字为Big Endian

ID3v2中的位顺序是最高有效位在先(MSB)。多字节数字中的字节顺序是最高有效字节在先(例如$ 12345678将被编码为$ 12 34 56 78)。

contentFrame.contentSize但是,不进行任何转换这些字节也应该反转,如中所述ID3_sync_safe_to_int(),但是这次以8的倍数而不是7的倍数移位(或使用ntohl()-网络到主机顺序)。

您说得到的是1677772160而不是18,但是即使对上面的位/字节进行了操作,它们似乎也没有意义。您确定这些数字正确吗?在您的帖子之上,您还有其他价值:

与其给我不足100个字节的完整记录,不如给我大约140000个字节。

调用后,您是否查看了内存中的字节file.read((char*)&contentFrame, FRAMESIZE);但是,如果您的身份证显示TPE1位置应该可以。我只是想知道您提供的数字是否正确,因为它们没有意义。

更新nthol()转换:

//Read frame header
file.read((char*)&contentFrame, FRAMESIZE);
uint32_t frame_size = ntohl(contentFrame);
cout << "Frame size: " << frame_size << endl;

ntohl()将在LE系统BE系统上运行(在BE系统上,它不会运行)。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章