M4A格式的ID3信息提取
由于产品的音乐播放器上需要支持对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信息提取相关推荐
- 在线qmc0转换mp3工具_如何将M4A格式的音频转换为MP3格式?只需一步搞定
随着网络技术的发达,会有很多人喜欢在网上下载东西,特别是很喜欢在网上下载音乐,但是下载音乐之后发现是M4A格式?这样用起来很不方便,都喜欢MP3格式的,那么如何将M4A格式的音频转换为MP3格式?今天 ...
- 电脑下载的M4A格式文件怎么转换为MP3格式
M4A文件格式并不是一个家喻户晓的名字,与MP3格式相比,知名度远远落后.但是,这并不意味着它无关紧要,有时候我们下载的音乐可能就是M4A格式的,如果换一个设备播放可能就会出现格式不兼容无法播放的情况 ...
- python m4a转mp3_python脚本实现音频m4a格式转成MP3格式
群里看到有人询问:谁会用python将微信音频文件后缀m4a格式转成mp3格式,毫不犹豫回了句:我会.然后就私下聊起来了 解决方法介绍如下: 工具:windows系统,python2.7,转换库ffm ...
- 利用python实现m4a格式到MP3的转换
实现m4a格式到MP3的转换 前言 安装ffmpeg库 安装pydub库 代码主体 前言 \quad 因为会议海报需要录制音频解说,但是手机录音机默认的格式是m4a的格式,不符合mp3的格式要求,所以 ...
- m4a格式怎么转换成mp3,非常简单
m4a格式怎么转换成mp3?m4a是一种文件的扩展名,确切的说是一种音频文件格式. 为了区分mpeg-4中的音频和视频文件,苹果率先使用m4a格式替换了mpeg-4中的音频文件扩展名. 因为m4a主要 ...
- 华为手机录音m4a格式怎么转换为MP3格式
大家都知道,华为手机的录音格式一般是m4a格式,但是我们一般常见的音频格式是MP3格式,如果我们录了一段比较有趣的音频,分享给朋友,但是对方由于手机型号不同,无法打开,那岂不是很可惜?M4A格式的音质 ...
- 如何将m4a格式音频转为mp3?
如何将m4a格式音频转为mp3?如果你是苹果手机用户,那么你可能会发现一个问题,当我们将苹果手机的录音文件放到其它设备上时,可能会出现无法打开播放的情况,这是因为格式不被兼容的原因所引起的.苹果手机的 ...
- 电脑下载的M4A格式文件怎么转换为MP3格式 1
M4A文件格式并不是一个家喻户晓的名字,与MP3格式相比,知名度远远落后.但是,这并不意味着它无关紧要,有时候我们下载的音乐可能就是M4A格式的,如果换一个设备播放可能就会出现格式不兼容无法播放的情况 ...
- 如何将M4A格式的音频转换为MP3格式?只需一步搞定
随着网络技术的发达,会有很多人喜欢在网上下载东西,特别是很喜欢在网上下载音乐,但是下载音乐之后发现是M4A格式?这样用起来很不方便,都喜欢MP3格式的,那么如何将M4A格式的音频转换为MP3格式?今天 ...
最新文章
- 性能测试分享:系统架构
- 面试题:mysql 数据类型
- 「Web2.0」的创造者表示:为Web3.0喝彩还为时尚早
- 高斯模糊java代码_OpenCV3 Java图形图像上的高斯模糊(Imgproc.GaussianBlur)
- System.Data.SQLite(SQLite ADO.NET 2.0的提供程序,已经包含Sqlite引擎)
- Android长时间后台运行Service
- DragDrop 注册失败的解决方法 转
- 我国计算机发展历程简述,简述计算机的发展历程??
- 【计算机网络】数字签名和数字认证
- WebRTC源码研究(46)WebRCT统计信息
- python哥德巴赫猜想_Python验证哥德巴赫猜想
- linux无线网卡驱动编写,博通无线网卡驱动linux版
- linux学习系列-一些知识
- 给设计师的建设性反馈
- android广播内容显示在屏幕上,如何将手机屏幕投影到计算机显示器上?
- 连续支付(周期扣款)功能开发及注意事项
- vs java_VSCode搭建Java开发运行环境
- 【数据分析】黑色星期五(代码2)销售额分析1、2
- 【电力系统分析】同步发电机
- Android百度鹰眼轨迹