最近在用qt5編寫播放器時遇到個問題,在Windows端需要解析音頻文件音譜來繪製曲線圖,但發現Windows端的庫要麼太老、要麼太弱雞、要麼得自己編譯,無奈花了一天時間在下載、編譯taglib、學習ffmpeg路上,到最後都是以動態庫調用時出現未知函數告終(mingw_gcc),原來qt本身就有對這些的封裝,可採用qmediaplaer代替他們,只不過需要安裝解碼器纔行,但qmediaplaer並不支持ffmpeg、taglib的音頻文件直接操作功能,這不得已自己重寫一版。。。
參考文章
MP3文件結構解析(超詳細)
要一個解析MP3的代碼要C語言的 要自己寫的不要網上的
Inside the MP3 Codec - Page 11
lets-build-mp3-decoder
Reading MP3 files [closed]
C語言結構體爲
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版本可以通過音樂文件末尾倒數第128字節開始進行數據截取,這也是最簡單的
//用於解析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:ID3v2.3版本在國內只有原理講解文章與一些開源第三方庫可供參考
我這裏實現了一版非常爛的demo,望各位懂這方面的大佬幫忙指點指點
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();
}