由于产品的音乐播放器上需要支持对M4A格式文件的ID3信息和专辑封面信息的显示,查了相关资料,对照M4A的二进制文件,捣鼓出了M4A格式(实际上就是MP4的音频信息)简单的ID3信息及专辑封面的方法。
1、MP4(或M4A)文件开头数据字节结构
+--------------------------------+
| Header Size (4 bytes) |大小是按字节顺序存储
+--------------------------------+
| 固定标记 (4 bytes)ftyp |
+--------------------------------+
|类型 (8 bytes) M4A、mp42、isom等|
+--------------------------------+
| 剩余字节为ASCII编码的字符串信息|
+--------------------------------+
2、此后每一个ATOM的结构都是:4个字节的长度+4个字节的标识符
3、ATOM之间具有包含关系,当A包含B时且B是A的第一个子ATOM,格式如下:
XXXX AAAA xxxx BBBB xxxx CCCC ....
其中XXXX4个字节表示出标记为AAAA的ATOM的总的大小
后续子ATOM包含在这个总的大小之内
也就是XXXX = 8 + xxxx(B) + xxxx(C) + ...
上式中的8表示4个长度字节XXXX以及4个标识符字节AAAA
4、具体包含关系作者也没搞明白,这里仅仅对照m4a格式的二进制文件分析出标签及封面信息如何解析;
下面给出实现类的代码,里面用到的图片数据类可以在ID3标签解析的文章中看到。
解析类头文件代码如下:
/********************************************************************
Copyright(c) 2013, All rights reserved.
purpose: 提取MP4格式中的标签TAG信息类,多用于M4A音频文件
当前版本: 1.0
作 者: zhangwf
创建日期: 2013:2:21
完成日期:
取代版本:
作 者:
完成日期:
*********************************************************************/
#ifndef CMY_MP4_TAG_H_
#define CMY_MP4_TAG_H_
//
#include "CMyPicInfo.h"
#include <string>
using namespace std;
/*************************************************************************
1、MP4(或M4A)文件开头数据字节结构
+--------------------------------+
| Header Size (4 bytes) |大小是按字节顺序存储
+--------------------------------+
| 固定标记 (4 bytes)ftyp |
+--------------------------------+
|类型 (8 bytes) M4A、mp42、isom等|
+--------------------------------+
| 剩余字节为ASCII编码的字符串信息|
+--------------------------------+
2、此后每一个ATOM的结构都是:4个字节的长度+4个字节的标识符
3、ATOM之间具有包含关系,当A包含B时且B是A的第一个子ATOM,格式如下:
XXXX AAAA xxxx BBBB xxxx CCCC ....
其中XXXX4个字节表示出标记为AAAA的ATOM的总的大小
后续子ATOM包含在这个总的大小之内
也就是XXXX = 8 + xxxx(B) + xxxx(C) + ...
上式中的8表示4个长度字节XXXX以及4个标识符字节AAAA
4、具体包含关系作者也没搞明白,这里仅仅对照m4a格式的二进制文件分析出标签及封面信息如何解析;
*************************************************************************/
// 定义SIZE结构
struct MP4TAGSIZE
{
unsigned char ByteBuf[4];
};
class CMyMP4Tag
{
public: // 接口函数
// 解析文件,成功后调用下面接口获取信息
bool AnalyzeFile(const char *filePathName);
bool AnalyzeFile(const wchar_t *filePathName);
bool AnalyzeFile(const wstring &filePathName);
// 是否解析成功
bool BeSuccess();
// 获取标签信息接口
const char *GetTitle();
const char *GetArtist();
const char *GetAlbum();
const char *GetYear();
const char *GetGenre();
// 获取封面图片
const unsigned char* GetPicAddr(unsigned long *pPicSize=NULL);
// 取得封面图片的大小
unsigned long GetPicSize();
// 保存图片到文件
bool SavePicToFile(const char *filePathName);
bool SavePicToFile(const wchar_t *filePathName);
public: // 静态接口函数
// 计算SIZE大小
static unsigned long GetSize(const MP4TAGSIZE &tagSize);
public:
// 构造函数
CMyMP4Tag();
// 析构函数
~CMyMP4Tag();
private: // 私有成员函数
// 清除信息
void ClearDataInfo();
// 根据ATOM的ID及处理实际数据
bool HandleRealDataBuf(
unsigned int atomID,
const unsigned char *pRealBuf,
unsigned int unRealBytes
);
// UTF8转UNICODE
bool Utf8ToUnicode(
const unsigned char *pUtf8Buf,
unsigned int cbBufSize,
wstring &strUnicode
);
// UNICODE转ASCII
bool UnicodeToAscii(
const wchar_t *pUnicodeBuf,
unsigned int cchBufSize,
string &strAscii
);
private: // 私有成员变量
bool m_bAnalyzeSuccess; // 保存解析是否成功
string m_strTitle;
string m_strArtist;
string m_strAlbum;
string m_strYear;
string m_strGenre;
CMYPICINFO m_CoverPic;
private:
// 防止使用拷贝构造函数和赋值函数
CMyMP4Tag(const CMyMP4Tag &other);
CMyMP4Tag& operator=(const CMyMP4Tag &other);
};
//
#endif
实现文件如下:
/********************************************************************
Copyright(c) 2013, All rights reserved.
purpose: 提取M