我试图用c ++读取一个mp3文件,并显示该文件包含的id3信息。我遇到的问题是当我读取帧头时,它所持有的内容大小是错误的。而不是给我一个10字节的整数,它给了我167772160字节。 http://id3.org/id3v2.3.0#ID3v2_frame_overview
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;
上面的代码用于将二进制数据转换为ASCCI数据。 主要内部
my($tag, $ver, $rev, $flags, $size) = unpack("Z3 C C C N"), "header");
my($frameID, $FrameContentSize, $frameFlags) = unpack("Z4 N C2", "content");
我已经在 Perl 中为此任务编写了一个程序,它运行正常,使用unpack如:
<a id="search_btn" data-role="button" class="ui-btn ui-corner-all ui-shadow ui-btn-inline ui-icon-search ui-btn-icon-left">Show me the players</a>
sync_safe_to_int也用于使标题的大小正确,但对于竞争大小,它只打印无任何转换
N“网络”(大端)命令中的无符号长(32位)。
C无符号字符(八位字节)值。
Z以空值终止(ASCIZ)的字符串,将为空填充。
我程序的输出:
标题内容
标签:ID3
Ver:3
Rev:0
标志:0
尺寸:699
错误的输出!
框架内容
ID:TPE1
尺寸:167772160
旗帜:
更正Perl的输出!
框架内容
ID:TPE1
尺寸:10
标志:0
答案 0 :(得分:1)
contentFrame.contentSize
定义为uint32_t
,但打印为(signed)int
。
此外,由于document 状态多字节数字为 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);
后你看过内存中的字节了吗?但是,如果您的ID显示TPE1
,则该位置应该没问题。我只是想知道你提供的数字是否正确,因为它们没有意义。
使用nthol()
转化更新:
//Read frame header
file.read((char*)&contentFrame, FRAMESIZE);
uint32_t frame_size = ntohl(contentFrame);
cout << "Frame size: " << frame_size << endl;
ntohl()
将在BE系统上的LE系统和上运行(在BE系统上,它根本不会这样做)。
答案 1 :(得分:1)
而不是您最初发布的1677772160,而您获得的值是167772160,即0x0A000000,它立即显示您的字节与您期望的0x0000000A(十进制10)相反
您已安排Perl使用N格式以big-endian格式读取此内容,但您的C代码使用简单的uint32_t
,这是依赖于硬件的,可能是小端的
您需要为此字段编写一个字节反转子例程,其行为与标头字段的ID3_sync_safe_to_int
相同,但使用该值的所有32位。像这样的东西
uint32_t reverse_endian(uint32_t val)
{
typedef union {
uint32_t val;
uint8_t byte[4];
} split;
split *original = (split *) &val;
split new;
new.byte[0] = original->byte[3];
new.byte[1] = original->byte[2];
new.byte[2] = original->byte[1];
new.byte[3] = original->byte[0];
return new.val;
}
答案 2 :(得分:0)
好吧我不确定你是否正确地用{{1}}方法解释了你的帧大小。
编辑:我不知道导致此问题的原因,但您可以单独使用fread阅读框架大小或执行此操作:
{{1}}