600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > java获取专辑封面_从MP3中读取专辑封面图片

java获取专辑封面_从MP3中读取专辑封面图片

时间:2024-02-13 09:35:37

相关推荐

java获取专辑封面_从MP3中读取专辑封面图片

首先判断MP3文件中是否含有ID3V2的标签,关于ID3V2的格式有一堆的说法

我嘛,不怎么关心,因此只攻专辑图片,也就是判断是否包含APIC这个标识

找到这个标识其实也就是和解析普通文件一样,每个像APIC标识的东西,都有帧标识头和帧标识内容组成,有头中得出帧内容的实际长度即可,然后将数据读出就行啦

但是对于APIC标识,读出了内容,直接保存为文件并不能显示图片,因为这个帧内容的前面一部分用于记录图片的类型,之后还有一部分空数据,这里就需要些判断

我用的mp3文件大部分都是jpeg的图片,在APIC帧内容中开头就是image/jpeg,这种内容,由于JPEG图片以0xFFD8开始,因此只要判断帧内容中以0xFFD8开始即可获取真正的图片数据,当然了,其他的数据格式,我就没有判断了,现在附上C++代码

#include

#include

#include

#include

#include

int ReadAIPCFromMP3(const char* path);

int main(int argc, char *argv[])

{

ReadAIPCFromMP3("/Users/apple/Downloads/Avicii - The Nights.mp3");

return 0;

//QCoreApplication a(argc, argv);

//return a.exec();

printf("cannot open this mp3\n");

//return 0;

}

bool isFrameAPIC(const char* cID3V2Fra_head)

{

// 在win7中vs下,没发现strncasecmp函数,不然不需要两次判断

// 当然了,这种判断也可以逐字节判断

if ((strncmp(cID3V2Fra_head, "APIC", 4) == 0) ||

(strncmp(cID3V2Fra_head, "apic", 4) == 0))

return true;

return false;

}

int calcID3V2Len(const char* cID3V2_head)

{

int len = (cID3V2_head[6] & 0x7f) << 21

| (cID3V2_head[7] & 0x7f) << 14

| (cID3V2_head[8] & 0x7f) << 7

| (cID3V2_head[9] & 0x7f);

return len;

}

int calclID3V2FraLength(const char* cID3V2Fra_head)

{

int len = (int)(cID3V2Fra_head[4] * 0x100000000 +

cID3V2Fra_head[5] * 0x10000 +

cID3V2Fra_head[6] * 0x100 +

cID3V2Fra_head[7]);

return len;

}

bool isJPEG(const char* data)

{

// JPEG格式数据的起始为0xFFD8,当然了,结束也有标志,但是这里不需要了

if (((unsigned char)data[0] == 0xFF) &&

((unsigned char)data[1] == 0xD8))

return true;

return false;

}

int ReadAIPCFromMP3(const char* path)

{

FILE* fp = fopen(path, "rb");

if (!fp)

{

printf("cannot open this mp3\n");

return -1;

}

// 这里的ID3V2以及帧标识的大小由标准规定均为10个字节

// 这里其实应该是作为字节存储,用unsigned char更好,这里就简单用char替代吧

char cID3V2_head[10] = {0}, cID3V2Fra_head[10] = {0};

long ID3V2_len = 0, lID3V2Fra_length = 0;

char* cID3V2Fra = NULL;

// 读取帧头,这里就是为了判断是否是ID3V2的标签头

fread(cID3V2_head, 10, 1, fp);

if ((cID3V2_head[0] == 'I' || cID3V2_head[0] == 'i') &&

(cID3V2_head[1] == 'D' || cID3V2_head[1] == 'd') &&

cID3V2_head[2] == '3')

{

// 获取ID3V2标签的长度

ID3V2_len = calcID3V2Len(cID3V2_head);

}

bool hasAPIC = false;

// 这里来逐个读取帧标识,这里的专辑图片即保存在APIC标识里

while ((ftell(fp) + 10) <= ID3V2_len)

{

// 这里每个帧标识的长度也为10,由于每个帧标识的存储的数据的长度不一

// 每次要读取出来,进行运算获取真正数据长度

memset(cID3V2Fra_head, 0, 10);

fread(cID3V2Fra_head, 10, 1, fp);

lID3V2Fra_length = (cID3V2Fra_head[4] * 0x100000000 +

cID3V2Fra_head[5] * 0x10000 +

cID3V2Fra_head[6] * 0x100 +

cID3V2Fra_head[7]);

// 这里判断是否为专辑图片的帧标识

if (isFrameAPIC(cID3V2Fra_head))

{

cID3V2Fra = (char*)calloc(lID3V2Fra_length, 1);

if (cID3V2Fra != NULL)

{

hasAPIC = true;

fread(cID3V2Fra, lID3V2Fra_length, 1, fp);

}

break;

}

else

{

// 移动到下一帧标识

fseek(fp, lID3V2Fra_length, SEEK_CUR);

}

}

fclose(fp);

// 到这里如果,专辑图片要么读出,要么就不存在

if (hasAPIC)

{

// 这里整个数据的前面一部分数据是用来记录专辑图片的格式

// 例如 image/jpeg image/png等,这里大部分的专辑图片都是jpeg的

// 因此这里简单的只判断jpeg的格式,除去图片格式,数据前部依然有些是空数据

// 因此以jpeg的标识来定位图片数据的起始

int start = 0;

while (start < lID3V2Fra_length)

{

if (isJPEG(cID3V2Fra + start))

break;

++start;

}

// 是以JPEG格式存在,则存储为jpeg的文件

if (start != lID3V2Fra_length)

{

// 这里没有错误处理,从简

FILE* jpegFP = fopen("/Users/apple/Downloads/test.jpeg", "wb");

fwrite(cID3V2Fra + start, lID3V2Fra_length - start, 1, jpegFP);

fclose(jpegFP);

}

}

return 0;

}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。