Recently, I encountered a problem when writing a player with qt5. On the Windows side, I needed to analyze the audio spectrum of the audio file to draw a graph. However, I found that the library on the Windows side was either too old, too weak, or had to be compiled by myself. It took me a day. The time is on the way of downloading, compiling taglib, and learning ffmpeg. In the end, it ends up with unknown functions (mingw_gcc) when the dynamic library is called. It turns out that qt itself has these packages. You can use qmediaplaer to replace them, but you need to install a decoder It will work, but qmediaplaer does not support the direct operation function of audio files of ffmpeg and taglib, so it has to rewrite a version by itself. . .
Refer to the article
MP3 file structure analysis (ultra-detailed)
. You need a code to parse MP3. You need to write it yourself in C language. You don’t need the Internet
Inside the MP3 Codec - Page 11
lets-build-mp3-decoder
Reading MP3 files [closed]
The C language structure is
ID3V2
//起始位置:0x0-0x9
struct ID3V2Header{
char Header[3]; /*必须为“ID3”否则认为标签不存在*/
char Ver[1]; /*版本号ID3V2.3 就记录3*/
char Revision[1]; /*副版本号此版本记录为0*/
char Flag[1]; /*标志字节,只使用高三位,其它位为0 */
char Size[4]; /*标签大小*/
};
//起始位置:0x10-0x19
struct ID3V2INFO{
char ID[4]; /*标识帧,说明其内容,例如作者/标题等*/
char Size[4]; /*帧内容的大小,不包括帧头,不得小于1*/
char Flags[2]; /*标志帧,只定义了6 位*/
};
ID3V1
//起始位置:-128
struct ID3V1HEAD{
char tag[3];//tag占用3字节
char musicname[30];//音乐标签占30字节
char artist[30];//歌曲作者占30字节
char album[30];//发行专辑占30字节
char year[4];//发行年份占4字节
char generic[30];//一些音乐的介绍以及其他杂七杂八内容占30字节
char type[1];//类型,占1字节
};
part1: ID3v1 version can start data interception from the penultimate 128th byte at the end of the music file, which is also the simplest
//用于解析mp3文件,采用id3v1取倒数128固定位置数据
MP3INFO MediaTools::toMp3Info(QString path) {
int part = 128;
QString tag, musicname, artist, album, year, generic, musictype;
QFile f(path);
f.open(QFile::ReadOnly);//以只读方式打开文件
f.seek(f.size() - part);//从倒数128开始读取数据
part = part - 3;
tag = QString::fromLocal8Bit(f.readLine(4));//前3字节为tag标签,这里为什么用4,因为这是qt
f.seek(f.size() - part);
part = part - 30;//这里减去30,是为了给下面往后移动30字节读取内容
musicname = QString::fromLocal8Bit(f.readLine(31));
f.seek(f.size() - part);
part = part - 30;
artist = QString::fromLocal8Bit(f.readLine(31));
f.seek(f.size() - part);
part = part - 30;
album = QString::fromLocal8Bit(f.readLine(31));
f.seek(f.size() - part);
part = part - 4;
year = QString::fromLocal8Bit(f.readLine(5));
f.seek(f.size() - part);
part = part - 30;
generic = QString::fromLocal8Bit(f.readLine());
f.seek(f.size() - 1);
musictype = QString::fromLocal8Bit(f.readLine(1));
f.close();
//返回mp3info对象,可以用结构体代替
return MP3INFO(tag, musicname, artist, album, year, generic, musictype);
}
part2: The ID3v2.3 version only has principle explanation articles and some open source third-party libraries for reference in China.
I have implemented a very bad demo here. I hope everyone who understands this aspect can help give pointers
void MediaTools::seekFiles(int &len, QFile &f) {
QByteArray by;//创建一个字节数组对象
f.seek(len);//设置文件读取起始位置
//这个为音乐文件里0x21起始头部的帧信息头部,占4字节
qDebug() << "seekFiles 0 ::" << QString::fromLocal8Bit(f.readLine(5));
f.seek(len + 4);
//这个为音乐文件里帧内容大小
by = f.read(4);
qDebug() << "seekFiles 1 ::" << by;
f.seek(len + 4 + 4);
qDebug() << "seekFiles 2 ::" << QString::fromLocal8Bit(f.readLine(3));
int FSize;
//帧内容大小计算公式
FSize = by[0] * 0x100000000 + by[1] * 0x10000 + by[2] * 0x100 + by[3];
qDebug() << "seekFiles fsize ::" << FSize;
f.seek(len + 11);
qDebug() << "seekFiles data ::" << QString::fromLocal8Bit(f.readLine());
len = len + 10 + FSize;
qDebug() << "next positi ::: " << len << "\n";
}
//第一次调用位置
void MediaTools::Mp3ID3V2_3(QString path) {
QFile f(path);
f.open(QFile::ReadOnly);
QByteArray by;
//读取0x0-0x9位置的数据
qDebug() << "0 ::" << QString::fromLocal8Bit(f.readLine(4));//tag标识
f.seek(3);
qDebug() << "1 ::" << QString::fromLocal8Bit(f.readLine(2));
f.seek(4);
qDebug() << "2 ::" << QString::fromLocal8Bit(f.readLine(2));
f.seek(5);
qDebug() << "3 ::" << QString::fromLocal8Bit(f.readLine(2));
f.seek(6);
//帧数据内容大小,这里的大小为所有帧的内容大小,也就是说,在这个地址往后偏移1位就是音频数据了
by = f.read(4);
qDebug() << "4 ::" << by;
int len = 10;
int total_size;
total_size = (by[0] & 0x7F) * 0x200000 + (by[1] & 0x7F) * 0x400 +
(by[2] & 0x7F) * 0x80 + (by[3] & 0x7F);
qDebug() << total_size;
//通过不断的调用来获取音频文件里TIT2、TPE1、TALB等内容信息
seekFiles(len, f);
seekFiles(len, f);
seekFiles(len, f);
seekFiles(len, f);
seekFiles(len, f);
seekFiles(len, f);
seekFiles(len, f);
seekFiles(len, f);
f.close();
}