gpt4 book ai didi

c - 读取MP3 IDV2标签大小

转载 作者:行者123 更新时间:2023-11-30 15:02:18 25 4
gpt4 key购买 nike

我正在尝试读取 ID3V2 标签的大小。我的代码应该存储第一个 header ,其中包含此结构中的标识、版本、标志和大小。代码从位 0 读取到位 9 并将其存储在这里

typedef struct
{
uint32_t id:24; //"ID3"
uint16_t version; // $04 00
uint8_t flags; // %abcd0000
uint32_t size; //4 * %0xxxxxxx
}__attribute__((__packed__))
ID3TAG;

内容为:

fread(tag, sizeof(ID3TAG), 1, media);

然后将 tag.size 的值传递给该函数,该函数对大小的位进行非同步安全:

int unsynchsafe(uint32_t in)
{
int out = 0, mask = 0x7F000000;

while (mask) {
out >>= 1;
out |= in & mask;
mask >>= 8;
}

return out;
}

但是,synchsafe 的返回值永远不可能只是 header 的正确大小。我得到了 248627840。我使用 exif 工具仔细检查,结果不正确。我真的很感激任何形式的帮助

最佳答案

您遇到的问题与字节顺序有关。我假设您正在 x86 系统或其他小端系统上工作。 ID3 documentation 指出:

The byteorder in multibyte numbers is most significant byte first (e.g. $12345678 would be encoded $12 34 56 78).

因此,大小作为大端数字存储在文件中。将文件的字节读入 struct 后,需要将此字节顺序转换为小端字节序,然后删除四个零位以获得 size< 的最终 28 位表示形式。这也是为什么您必须将 tag->id0x334449 而不是 0x494433 进行比较 - 存储在 tag-> 中的字节id 作为多字节值访问,并以小端顺序解释。

以下是我为实现此目的所做的更改。我稍微更改了您的 struct ,使用 uint8_t 数组来获取正确的字节数。我还使用 memcmp() 来验证 tag->id。我大量使用了 unsignedunsigned long 类型,以避免位移位问题。到小端字节序的转换是原始的,并假设 8 位字节。

这是您在第一篇文章中链接到的整个文件,以及我的更改。我将 mp3 文件更改为我可以测试的文件。

#include <stdint.h>
#include <stdio.h>
#include <string.h> // for memcmp()

/**
** TAG is always present at the beggining of a ID3V2 MP3 file
** Constant size 10 bytes
**/

typedef struct
{
uint8_t id[3]; //"ID3"
uint8_t version[2]; // $04 00
uint8_t flags; // %abcd0000
uint32_t size; //4 * %0xxxxxxx
}__attribute__((__packed__))
ID3TAG;

unsigned int unsynchsafe(uint32_t be_in)
{
unsigned int out = 0ul, mask = 0x7F000000ul;
unsigned int in = 0ul;

/* be_in is now big endian */
/* convert to little endian */
in = ((be_in >> 24) | ((be_in >> 8) & 0xFF00ul) |
((be_in << 8) & 0xFF0000ul) | (be_in << 24));

while (mask) {
out >>= 1;
out |= (in & mask);
mask >>= 8;
}

return out;
}

/**
** Makes sure the file is supported and return the correct size
**/
int mp3Header(FILE* media, ID3TAG* tag)
{
unsigned int tag_size;

fread(tag, sizeof(ID3TAG), 1, media);

if(memcmp ((tag->id), "ID3", 3))
{
return -1;
}

tag_size = unsynchsafe(tag->size);
printf("tag_size = %u\n", tag_size);

return 0;
}

// main function
int main(void)
{
// opens the file
FILE* media = fopen("cognicast-049-carin-meier.mp3", "r");

//checks if the file exists
if(media == NULL)
{
printf("Couldn't read file\n");
return -1;
}

ID3TAG mp3_tag;
// check for the format of the file
if(mp3Header(media, &mp3_tag) != 0)
{
printf("Unsupported File Format\n");
fclose(media);
return -2;
}
fclose(media);

return 0;
}

顺便说一句,C 标准库中已经有一个函数可以执行此转换。 ntohl() 位于 netinet/in.h 头文件中,它从网络字节顺序转换 uint32_t 数字(这是 big- endian)到主机字节顺序。如果您的系统是大尾数法,则该函数将返回输入值不变。但如果您的系统是小端字节序,则输入将转换为小端字节序表示形式。这对于使用不同字节排序约定的计算机之间传递数据非常有用。还有相关函数 htonl()htons()ntohs()

可以将上面的代码更改为(更好)以使用 ntohl(),方法是将我的原始转换代码替换为:

#include <netinet/in.h>  // for ntohl()
...
/* convert to host-byte-order (little-endian for x86) */
in = ntohl(be_in);

关于c - 读取MP3 IDV2标签大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41087999/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com