由于产品的音乐播放器上需要支持对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转UNICODEbool Utf8ToUnicode(const unsigned char *pUtf8Buf,unsigned int cbBufSize,wstring &strUnicode);// UNICODE转ASCIIbool 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:    提取MP4格式中的标签TAG信息类,多用于M4A音频文件当前版本:   1.0作    者:   zhangwf创建日期:   2013:2:21完成日期:   取代版本:作    者:完成日期:
*********************************************************************/
#include "CMyMP4Tag.h"
#include <Windows.h>
//
// 音乐流派
const unsigned int GENREG_ARRAY_SIZE = 148;    // 流派总数
const char *GENREG_MYGenreTable[GENREG_ARRAY_SIZE + 1] =
{"Blues",             "Classic Rock",               "Country",                "Dance",              "Disco",              "Funk",         // 0-5"Grunge",             "Hip-Hop",                    "Jazz",                   "Metal",              "New Age",                "Oldies",       // 6-11"Other",             "Pop",                        "R&B",                    "Rap",                    "Reggae",             "Rock",         // 12-17"Techno",               "Industrial",             "Alternative",            "Ska",                    "Death Metal",            "Pranks",       // 18-23"Soundtrack",           "Euro-Techno",                "Ambient",                "Trip-Hop",               "Vocal",              "Jazz+Funk",    // 24-29"Fusion",              "Trance",                 "Classical",          "Instrumental",           "Acid",                   "House",        // 30-35"Game",                 "Sound Clip",             "Gospel",             "Noise",              "Alt. Rock",          "Bass",         // 36-41"Soul",                 "Punk",                       "Space",              "Meditative",         "Instrum. Pop",           "Instrum. Rock",// 42-47"Ethnic",               "Gothic",                 "Darkwave",               "Techno-Indust.",     "Electronic",         "Pop-Folk",     // 48-53"Eurodance",            "Dream",                  "Southern Rock",      "Comedy",             "Cult",                   "Gangsta",      // 54-59"Top 40",               "Christian Rap",          "Pop/Funk",               "Jungle",             "Native American",        "Cabaret",      // 60-65"New Wave",             "Psychadelic",                "Rave",                   "Showtunes",          "Trailer",                "Lo-Fi",        // 66-71"Tribal",               "Acid Punk",              "Acid Jazz",          "Polka",              "Retro",              "Musical",      // 72-77"Rock & Roll",          "Hard Rock",              "Folk",                   "Folk/Rock",          "National Folk",      "Swing",        // 78-83"Fusion",               "Bebob",                  "Latin",              "Revival",                "Celtic",             "Bluegrass",    // 84-89"Avantgarde",           "Gothic Rock",                "Progress. Rock",     "Psychadel. Rock",        "Symphonic Rock",     "Slow Rock",    // 90-95"Big Band",             "Chorus",                 "Easy Listening",     "Acoustic",               "Humour",             "Speech",       // 96-101"Chanson",             "Opera",                  "Chamber Music",      "Sonata",             "Symphony",               "Booty Bass",   // 102-107"Primus",             "Porn Groove",                "Satire",                                                                               // 108-110//extended"Slow Jam",             "Club",                       "Tango",              "Samba",              "Folklore",               "Ballad",       // 111-116"Power Ballad",           "Rhythmic Soul",          "Freestyle",          "Duet",                   "Punk Rock",          "Drum Solo",    // 117-122"A Capella",          "Euro-House",             "Dance Hall",         "Goa",                    "Drum & Bass",            "Club-House",   // 123-128"Hardcore",               "Terror",                 "Indie",              "BritPop",                "Negerpunk",          "Polsk Punk",   // 129-134"Beat",                   "Christian Gangsta Rap",  "Heavy Metal",            "Black Metal",            "Crossover",          "Contemporary Christian",// 135-140"Christian Rock",                                                                                                                           // 141// winamp 1.91 genres "Merengue",                "Salsa",                  "Thrash Metal",                                                                         // 142-144// winamp 1.92 genres "Anime",                "Jpop",                       "Synthpop",               "\0"                                                            // 145-147
};
//
// 定义用到的ATOM的ID
enum CMP4TAGATOM_ID
{CMP4TAGATOM_ERROR = 0,     // 初始化值CMP4TAGATOM_ALBUM,         // 专辑CMP4TAGATOM_ARTIST,        // 艺术家CMP4TAGATOM_NAME,          // 名称CMP4TAGATOM_DATE,          // 日期CMP4TAGATOM_GENRE,         // 流派CMP4TAGATOM_COVER,         // 封面
};// 构造函数
CMyMP4Tag::CMyMP4Tag()
{ClearDataInfo();
}// 析构函数
CMyMP4Tag::~CMyMP4Tag()
{}// 计算SIZE大小
unsigned long CMyMP4Tag::GetSize(const MP4TAGSIZE &tagSize)
{return (tagSize.ByteBuf[0]<<24) | (tagSize.ByteBuf[1]<<16) | (tagSize.ByteBuf[2]<<8) | tagSize.ByteBuf[3];
}// 解析文件,成功后调用下面接口获取信息
bool CMyMP4Tag::AnalyzeFile(const char *filePathName)
{// 清除上次信息ClearDataInfo();// 参数有效性if (filePathName == NULL){      return false;}// 打开文件FILE *pMp4File = fopen(filePathName, "rb");if (pMp4File == NULL){ return false;}// 读取头结构大小MP4TAGSIZE headSize = {0}; if (fread(&headSize, sizeof(headSize), 1, pMp4File) != 1){     fclose(pMp4File);return false;}// 紧接着读取4个字节判断是否ftypunsigned char cBuf[4] = {0};if (   fread(cBuf, sizeof(cBuf), 1, pMp4File) != 1|| cBuf[0] != 'f'|| cBuf[1] != 't'|| cBuf[2] != 'y'|| cBuf[3] != 'p'){       fclose(pMp4File);return false;}// 把文件指针移动到ATOM开始的位置fseek(pMp4File, GetSize(headSize)-8, SEEK_CUR);// 每个ATOM的格式都是4个字节的大小加上4个字节的标识符// 循环读取找出需要解析的标识符进行解析CMP4TAGATOM_ID currentAtom = CMP4TAGATOM_ERROR;memset(cBuf, 0, sizeof(cBuf));MP4TAGSIZE tagSize = {0};MP4TAGSIZE lenSize = {0};long lRealBytes = 0;unsigned char* pRealBuf = NULL;while (   fread(&tagSize, sizeof(tagSize), 1, pMp4File) == 1&& fread(cBuf, sizeof(cBuf), 1, pMp4File) == 1){// 清除上次ATOM的IDcurrentAtom = CMP4TAGATOM_ERROR;// 这些ATOM之后紧跟着是所属子层次的ATOM,不需要移动文件指针if (   (cBuf[0]=='m' && cBuf[1]=='o' && cBuf[2]=='o' && cBuf[3]=='v') // moov|| (cBuf[0]=='t' && cBuf[1]=='r' && cBuf[2]=='a' && cBuf[3]=='k') // trak|| (cBuf[0]=='m' && cBuf[1]=='d' && cBuf[2]=='i' && cBuf[3]=='a') // mdia|| (cBuf[0]=='m' && cBuf[1]=='i' && cBuf[2]=='n' && cBuf[3]=='f') // minf|| (cBuf[0]=='s' && cBuf[1]=='t' && cBuf[2]=='b' && cBuf[3]=='l') // stbl|| (cBuf[0]=='u' && cBuf[1]=='d' && cBuf[2]=='t' && cBuf[3]=='a') // udta|| (cBuf[0]=='i' && cBuf[1]=='l' && cBuf[2]=='s' && cBuf[3]=='t') // ilst,TAG信息都在这个ATOM之下){          continue;}// 此ATOM之后的4个字节是大小需要向后移动4个字节的文件指针else if ((cBuf[0]=='m' && cBuf[1]=='e' && cBuf[2]=='t' && cBuf[3]=='a')){            fseek(pMp4File, 4, SEEK_CUR);continue;}         // 解析专辑、艺术家、名称、年份日期,这些第一个字节值为0xA9else if (cBuf[0] == 0xA9){                        // 专辑if (cBuf[1]=='a' && cBuf[2]=='l' && cBuf[3]=='b'){currentAtom = CMP4TAGATOM_ALBUM;}// 艺术家else if (cBuf[1]=='A' && cBuf[2]=='R' && cBuf[3]=='T'){currentAtom = CMP4TAGATOM_ARTIST;}// 名称else if (cBuf[1]=='n' && cBuf[2]=='a' && cBuf[3]=='m'){   currentAtom = CMP4TAGATOM_NAME;}// 日期else if (cBuf[1]=='d' && cBuf[2]=='a' && cBuf[3]=='y'){currentAtom = CMP4TAGATOM_DATE;}          }// 解析流派else if (cBuf[0]=='g' && cBuf[1]=='n' && cBuf[2]=='r' && cBuf[3]=='e'){         currentAtom = CMP4TAGATOM_GENRE;           }// 解析封面图片else if (cBuf[0]=='c' && cBuf[1]=='o' && cBuf[2]=='v' && cBuf[3]=='r'){   currentAtom = CMP4TAGATOM_COVER;           }//// 是需要解析的ATOMif (currentAtom != CMP4TAGATOM_ERROR){// 给出需要解析的ATOM的格式及实际数据例子如下// |    XXXX     |     AAAA     |    xxxx     |     data    |    ver    |   flag   |  reserved   | realdata    |//  总长度4字节     标识符4字节   长度4字节    固定符号4字节     1字节      3字节     保留4字节    剩余实际数据// | 00 00 00 1C | A9 61 6C 62  | 00 00 00 14 | 64 61 74 61 |     00    | 00 00 01 | 00 00 00 00 | 43 43 43 43 |//     总长28      标识符A9alb      长度20       字符data                                          实际数据CCCC// 其中流派的实际数据为2个字节,给出的是索引值,需要拿这个索引值在流派类型数组中取出流派字符串// 专辑、艺术家、名称、日期的实际数据是UTF-8编码// 封面的实际数据就是整个图片数据// 当前文件指针位置为长度xxxx的起始位置// 读取长度及标识符,读取失败直接跳出循环结束if (   fread(&lenSize, sizeof(lenSize), 1, pMp4File) == 1&& fread(cBuf, sizeof(cBuf), 1, pMp4File) == 1){// 计算实际数据长度lRealBytes = GetSize(lenSize) - 16;// 判断长度及标识符是否正确if (   GetSize(lenSize)+8 == GetSize(tagSize)&& cBuf[0] == 'd' && cBuf[1] == 'a' && cBuf[2] == 't' && cBuf[3] == 'a'&& lRealBytes > 0){// 当前文件指针位于ver开始处,向后移动8个字节到实际数据处fseek(pMp4File, 8, SEEK_CUR);// 申请存储空间,失败直接结束pRealBuf = new unsigned char[lRealBytes+1];if (pRealBuf == NULL){break;}memset(pRealBuf, 0, lRealBytes+1);                   // 读取实际数据if (fread(pRealBuf, lRealBytes, 1, pMp4File) == 1){                      // 根据ATOM类型解析实际读取的数据HandleRealDataBuf(currentAtom, pRealBuf, (unsigned int)lRealBytes);// 释放内存空间delete[] pRealBuf;pRealBuf = NULL;lRealBytes = 0;// 实际数据读取完成后,文件指针位于下一个ATOM的开始处continue;}// 发生读取文件错误直接结束else{delete[] pRealBuf;pRealBuf = NULL;lRealBytes = 0;break;}}// 格式不对,移动文件指针到下一个ATOM开始的位置,基本不会发生这种情况else{fseek(pMp4File, GetSize(tagSize)-8-8, SEEK_CUR);}}// 发生了读取文件失败则直接结束else{break;}}// 非解析ATOM,移动文件指针到下一个ATOM的开始位置else{            fseek(pMp4File, GetSize(tagSize)-8, SEEK_CUR);}             }// 读取成功关闭文件fclose(pMp4File);// 返回分析结果m_bAnalyzeSuccess = true;return m_bAnalyzeSuccess;
}// 根据ATOM的ID及处理实际数据
bool CMyMP4Tag::HandleRealDataBuf(unsigned int atomID,const unsigned char *pRealBuf,unsigned int unRealBytes        )
{// 参数有效性if (   atomID == CMP4TAGATOM_ERROR || pRealBuf == NULL|| unRealBytes == 0){return false;}// 其中流派的实际数据为2个字节,给出的是索引值,需要拿这个索引值在流派类型数组中取出流派字符串// 专辑、艺术家、名称、日期的实际数据是UTF-8编码// 封面的实际数据就是整个图片数据// 根据ATOM的类型处理bool bRet = true;switch (atomID){case CMP4TAGATOM_ALBUM: // 专辑{wstring strUnicode = L"";Utf8ToUnicode(pRealBuf, unRealBytes, strUnicode);UnicodeToAscii(strUnicode.c_str(), (unsigned int)strUnicode.length(), m_strAlbum);          }break;case CMP4TAGATOM_ARTIST: // 艺术家{wstring strUnicode = L"";Utf8ToUnicode(pRealBuf, unRealBytes, strUnicode);UnicodeToAscii(strUnicode.c_str(), (unsigned int)strUnicode.length(), m_strArtist);}break;case CMP4TAGATOM_NAME: // 名称{wstring strUnicode = L"";Utf8ToUnicode(pRealBuf, unRealBytes, strUnicode);UnicodeToAscii(strUnicode.c_str(), (unsigned int)strUnicode.length(), m_strTitle);}break;case CMP4TAGATOM_DATE: // 日期{wstring strUnicode = L"";Utf8ToUnicode(pRealBuf, unRealBytes, strUnicode);UnicodeToAscii(strUnicode.c_str(), (unsigned int)strUnicode.length(), m_strYear);}break;case CMP4TAGATOM_GENRE: // 流派{if (unRealBytes == 2){unsigned int unIndex = (pRealBuf[0]<<8) | pRealBuf[1];if (unIndex>0 && unIndex<GENREG_ARRAY_SIZE){m_strGenre = string(GENREG_MYGenreTable[unIndex-1]);}}}break;case CMP4TAGATOM_COVER: // 封面{m_CoverPic.SetPicBufData((const char*)pRealBuf, unRealBytes);}break;default:{bRet = false;}break;}return bRet;
}// UTF8转UNICODE
bool CMyMP4Tag::Utf8ToUnicode(const unsigned char *pUtf8Buf,unsigned int cbBufSize,wstring &strUnicode)
{// 初始化输出参数strUnicode = L"";// 参数有效性if (pUtf8Buf==NULL || cbBufSize==0){return false;}// 计算转换需要UNICODE字符数DWORD dwUnicodeChars = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pUtf8Buf, cbBufSize, NULL, 0);if (dwUnicodeChars == 0){       return false;}// 申请存放空间 wchar_t *pUnicodeBuf = new wchar_t[dwUnicodeChars+1];if (pUnicodeBuf == NULL){      return false;}// Convert Buf from ASCII to Unicode.memset(pUnicodeBuf, 0, (dwUnicodeChars+1)*sizeof(wchar_t));MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pUtf8Buf, cbBufSize, (LPWSTR)pUnicodeBuf, dwUnicodeChars);  // 得到输出内容strUnicode = wstring(pUnicodeBuf);// 释放临时缓冲区if (pUnicodeBuf != NULL){delete[] pUnicodeBuf;pUnicodeBuf = NULL;}// 成功返回return true;
}// UNICODE转ASCII
bool CMyMP4Tag::UnicodeToAscii(const wchar_t *pUnicodeBuf,unsigned int cchBufSize,string &strAscii)
{// 初始化输出参数strAscii = "";// 参数有效性if (pUnicodeBuf==NULL || cchBufSize==0){return false;}// 计算转换为多字节字节数int nChars = WideCharToMultiByte(CP_ACP, 0, pUnicodeBuf, cchBufSize, NULL, 0, NULL, NULL);// 申请空间char *pCharBuf = new char[nChars+1];if (pCharBuf == NULL){return false;}// 转换为多字节memset(pCharBuf, 0, nChars+1);WideCharToMultiByte(CP_ACP, 0, pUnicodeBuf, cchBufSize, pCharBuf, nChars, NULL, NULL);// 得到结果strAscii = string(pCharBuf);// 释放if (pCharBuf != NULL){delete[] pCharBuf;pCharBuf = NULL;}// 转换成功return true;
}bool CMyMP4Tag::AnalyzeFile(const wchar_t *filePathName)
{// 参数有效性if (filePathName == NULL){return false;}// 转换文件名string strFile = "";if (!UnicodeToAscii(filePathName, (unsigned int)wcslen(filePathName), strFile)){return false;}// 返回解析结果return AnalyzeFile(strFile.c_str());;
}bool CMyMP4Tag::AnalyzeFile(const wstring &filePathName)
{return AnalyzeFile(filePathName.c_str());
}// 是否解析成功
bool CMyMP4Tag::BeSuccess()
{return m_bAnalyzeSuccess;
}// 清除信息
void CMyMP4Tag::ClearDataInfo()
{m_bAnalyzeSuccess = false;m_strTitle = "";m_strArtist = "";m_strAlbum = "";m_strYear = "";m_strGenre = ""; m_CoverPic.ReleaseData();
}// 获取标签信息接口
const char* CMyMP4Tag::GetTitle()
{return m_strTitle.c_str();
}
const char* CMyMP4Tag::GetArtist()
{return m_strArtist.c_str();
}
const char* CMyMP4Tag::GetAlbum()
{return m_strAlbum.c_str();
}
const char* CMyMP4Tag::GetYear()
{return m_strYear.c_str();
}
const char* CMyMP4Tag::GetGenre()
{return m_strGenre.c_str();
}// 获取封面图片
const unsigned char* CMyMP4Tag::GetPicAddr(unsigned long *pPicSize)
{if (pPicSize != NULL){*pPicSize = m_CoverPic.GetPicBufSize();}return m_CoverPic.GetPicBufAddr();
}// 取得封面图片的大小
unsigned long CMyMP4Tag::GetPicSize()
{return m_CoverPic.GetPicBufSize();
}// 保存图片到文件
bool CMyMP4Tag::SavePicToFile(const char *filePathName)
{return m_CoverPic.SavePicToFile(filePathName);
}
bool CMyMP4Tag::SavePicToFile(const wchar_t *filePathName)
{return m_CoverPic.SavePicToFile(filePathName);
}

为了集成到其它格式的ID3解析接口中,上面只简单的给出了ASCII码的接口,需要的可以自己添加。

M4A格式的ID3信息提取相关推荐

  1. 在线qmc0转换mp3工具_如何将M4A格式的音频转换为MP3格式?只需一步搞定

    随着网络技术的发达,会有很多人喜欢在网上下载东西,特别是很喜欢在网上下载音乐,但是下载音乐之后发现是M4A格式?这样用起来很不方便,都喜欢MP3格式的,那么如何将M4A格式的音频转换为MP3格式?今天 ...

  2. 电脑下载的M4A格式文件怎么转换为MP3格式

    M4A文件格式并不是一个家喻户晓的名字,与MP3格式相比,知名度远远落后.但是,这并不意味着它无关紧要,有时候我们下载的音乐可能就是M4A格式的,如果换一个设备播放可能就会出现格式不兼容无法播放的情况 ...

  3. python m4a转mp3_python脚本实现音频m4a格式转成MP3格式

    群里看到有人询问:谁会用python将微信音频文件后缀m4a格式转成mp3格式,毫不犹豫回了句:我会.然后就私下聊起来了 解决方法介绍如下: 工具:windows系统,python2.7,转换库ffm ...

  4. 利用python实现m4a格式到MP3的转换

    实现m4a格式到MP3的转换 前言 安装ffmpeg库 安装pydub库 代码主体 前言 \quad 因为会议海报需要录制音频解说,但是手机录音机默认的格式是m4a的格式,不符合mp3的格式要求,所以 ...

  5. m4a格式怎么转换成mp3,非常简单

    m4a格式怎么转换成mp3?m4a是一种文件的扩展名,确切的说是一种音频文件格式. 为了区分mpeg-4中的音频和视频文件,苹果率先使用m4a格式替换了mpeg-4中的音频文件扩展名. 因为m4a主要 ...

  6. 华为手机录音m4a格式怎么转换为MP3格式

    大家都知道,华为手机的录音格式一般是m4a格式,但是我们一般常见的音频格式是MP3格式,如果我们录了一段比较有趣的音频,分享给朋友,但是对方由于手机型号不同,无法打开,那岂不是很可惜?M4A格式的音质 ...

  7. 如何将m4a格式音频转为mp3?

    如何将m4a格式音频转为mp3?如果你是苹果手机用户,那么你可能会发现一个问题,当我们将苹果手机的录音文件放到其它设备上时,可能会出现无法打开播放的情况,这是因为格式不被兼容的原因所引起的.苹果手机的 ...

  8. 电脑下载的M4A格式文件怎么转换为MP3格式 1

    M4A文件格式并不是一个家喻户晓的名字,与MP3格式相比,知名度远远落后.但是,这并不意味着它无关紧要,有时候我们下载的音乐可能就是M4A格式的,如果换一个设备播放可能就会出现格式不兼容无法播放的情况 ...

  9. 如何将M4A格式的音频转换为MP3格式?只需一步搞定

    随着网络技术的发达,会有很多人喜欢在网上下载东西,特别是很喜欢在网上下载音乐,但是下载音乐之后发现是M4A格式?这样用起来很不方便,都喜欢MP3格式的,那么如何将M4A格式的音频转换为MP3格式?今天 ...

最新文章

  1. 性能测试分享:系统架构
  2. 面试题:mysql 数据类型
  3. 「Web2.0」的创造者表示:为Web3.0喝彩还为时尚早
  4. 高斯模糊java代码_OpenCV3 Java图形图像上的高斯模糊(Imgproc.GaussianBlur)
  5. System.Data.SQLite(SQLite ADO.NET 2.0的提供程序,已经包含Sqlite引擎)
  6. Android长时间后台运行Service
  7. DragDrop 注册失败的解决方法 转
  8. 我国计算机发展历程简述,简述计算机的发展历程??
  9. 【计算机网络】数字签名和数字认证
  10. WebRTC源码研究(46)WebRCT统计信息
  11. python哥德巴赫猜想_Python验证哥德巴赫猜想
  12. linux无线网卡驱动编写,博通无线网卡驱动linux版
  13. linux学习系列-一些知识
  14. 给设计师的建设性反馈
  15. android广播内容显示在屏幕上,如何将手机屏幕投影到计算机显示器上?
  16. 连续支付(周期扣款)功能开发及注意事项
  17. vs java_VSCode搭建Java开发运行环境
  18. 【数据分析】黑色星期五(代码2)销售额分析1、2
  19. 【电力系统分析】同步发电机
  20. Android百度鹰眼轨迹

热门文章

  1. 在c语言中开辟一个数组空间,c语言如何在动态的结构体数组开辟新空间
  2. Unity实现Angry Bird弹弓发射功能
  3. 51CTO学院优惠版
  4. 定制传承银鲨耀世,iGame Z390旗舰电竞主板品鉴
  5. android手机如何截屏,安卓手机怎么截图? (全文)
  6. 如何用教科书式的方法,着手分析一个行业?
  7. 用Python写个「倒计时」软件
  8. tf.losses.mean_squared_error函数浅析
  9. python Shapely使用指南详解
  10. jBPM4的PVM实现解析