AAC介紹
介紹
AAC,全稱Advanced Audio Coding具则,是一種專為聲音數(shù)據(jù)設(shè)計的文件壓縮格式稼钩。他的目的是為了取代MP3格式,與MP3不同苟呐,它采用了全新的算法進(jìn)行編碼痒芝,更加高效,具有更高的“性價比”牵素。利用AAC格式严衬,可使人感覺聲音質(zhì)量沒有明顯降低的前提下,更加小巧笆呆。
為什么重點(diǎn)介紹AAC
1.他的應(yīng)用范圍廣请琳。目前市場上泛娛樂化直播系統(tǒng),90%以上都是采用AAC編碼
2.目前的傳輸協(xié)議赠幕,一般采用rtmp協(xié)議俄精,此協(xié)議支持aac,但是不支持OPUS??(因?yàn)镺PUS是最近才推出的榕堰,雖然強(qiáng)竖慧,但是還不通用)
3.AAC本身編解碼器質(zhì)量非常高。作為一種高壓縮比的音頻壓縮算法逆屡,AAC通常壓縮比為18:1??(也有資料說為20:1)圾旨,但是還能保存較好的音質(zhì)。
AAC音頻格式
ADIF (Audio Data Interchange Format)
這種格式只需要在文件開頭存一個很小的頭魏蔗,包括采樣率砍的,采樣大小,聲道數(shù)量等基本信息莺治,就可以對文件進(jìn)行解讀挨约。這種格式只能從頭開始解碼味混,常用在磁盤文件中。
ADTS (Audio Data transport Stream)
這種格式每一幀前面都有一個同步字诫惭,占用7-9個字節(jié),好處是可以在音頻流的任何位置開始解碼蔓挖,他類似于數(shù)據(jù)流格式夕土。因?yàn)槊恳粠懊娑加型阶郑訟DTS文件要比ADIF增加一些數(shù)據(jù)量
AAC產(chǎn)生原因
AAC產(chǎn)生目的就是為了取代MP3瘟判。
AAC之前怨绣,大部分音頻都還是使用MP3格式。MP3的使用規(guī)范是MPEG-2拷获,他對于音頻編解碼篮撑,主要思想還是有損壓縮。有損壓縮在《Android 音視頻之音頻入門講解》也介紹過匆瓜,被壓縮的數(shù)據(jù)不能完全還原回來赢笨,所以音質(zhì)上會有一定損耗。而且在碼率比較高的情況下驮吱,壓縮比要非常高的情況下茧妒,損耗性會非常大。AAC恰巧彌補(bǔ)了這個問題左冬,AAC對原始數(shù)據(jù)損耗很低桐筏,但是壓縮效率很高。
在2000年拇砰,MPEG-4標(biāo)準(zhǔn)出現(xiàn)后梅忌,AAC還加入了SBR技術(shù)和PS技術(shù)。
AAC LC :
LC (Low Complexity) 低復(fù)雜度
AAC HE V1 : AAC LC + SBR
SBR(Spectral Band Replication)是增頻復(fù)用除破。我們知道牧氮,音頻頻帶分為高頻和低頻。所以低頻的20hz皂岔,如果我們采用44.1khz的采樣率蹋笼,就采樣2000次,他就可以完整記錄下模擬聲波躁垛,但是我們沒必要進(jìn)行這么多的采樣剖毯。高頻的20khz,我們采用44.1khz的采樣率教馆,結(jié)果只采樣2次逊谋,這樣保真性就很差。而采用了SBR技術(shù)土铺,SBR把頻譜切割開來胶滋,低頻單獨(dú)編碼保存主要成分板鬓, 高頻單獨(dú)放大編碼保存音質(zhì),這樣高頻就增加了采樣究恤。這樣的好處俭令,一是減少了碼率,二是提高了音頻的質(zhì)量部宿。
AAC HE V2 : AAC + SBR + PS
PS(Parametric Stereo)是雙聲道分別保存抄腔,一個聲道完整保存,另一個只存差異的理张,參數(shù)的部分赫蛇。因?yàn)閮蓚€聲道相關(guān)性非常強(qiáng),我們可以通過某種函數(shù)雾叭,完全恢復(fù)以前的聲音悟耘。基于這些原因织狐,所以他只要存一些參數(shù)就可以了暂幼。
AAC優(yōu)點(diǎn)
①提升的壓縮率:可以以更小的文件大小獲得更高的音質(zhì);
②支持多聲道:可提供最多48個全音域聲道赚瘦;
③更高的解析度:最高支持96KHz的采樣頻率粟誓;
④提升的解碼效率:解碼播放所占的資源更少;
AAC編解碼庫
Libfdk_AAC > ffmpeg AAC > libaac > libvo_aacenc
AAC編碼使用
使用ffmpeg對音頻進(jìn)行AAC編碼
不好意思起意,前段時間想采用ffmpeg去對AAC進(jìn)行編碼鹰服,結(jié)果開發(fā)過程中,發(fā)現(xiàn)ffmpeg avcodec_encode_audio2返回-22揽咕,導(dǎo)致編碼不成功悲酷,一直找不到原因。后期修改好了亲善,我一定在文章和項(xiàng)目中補(bǔ)上设易。
使用MediaCodec對音頻進(jìn)行AAC硬編碼
????????Android中可以使用MediaCodec來訪問底層的媒體編解碼器,可以對媒體進(jìn)行編/解碼。
????????舉例,比如之前文章《Android 音視頻之音頻錄制》哼绑,我們使用AudioRecord錄制了一個pcm文件诅挑。我們要將文件數(shù)據(jù)進(jìn)行AAC編碼始赎,需要先初始化一個MediaCodec對象,設(shè)置他的MediaFormat為MediaFormat.MIMETYPE_AUDIO_AAC。如果想使用其他壓縮編碼,類似讼昆。代碼如下:
/**
* 初始化AAC編碼器
*/
private void initAACMediaEncode() {
try {
//參數(shù)對應(yīng)-> mime type、采樣率骚烧、聲道數(shù)
MediaFormat encodeFormat = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, 44100, 2);
encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, 64000);//比特率
encodeFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
encodeFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 100 * 1024);
mediaEncode = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
mediaEncode.configure(encodeFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
} catch (IOException e) {
e.printStackTrace();
}
if (mediaEncode == null) {
Log.e(TAG, "create mediaEncode failed");
return;
}
mediaEncode.start();
encodeInputBuffers = mediaEncode.getInputBuffers();
encodeOutputBuffers = mediaEncode.getOutputBuffers();
encodeBufferInfo = new MediaCodec.BufferInfo();
}
初始化編碼器后浸赫,將pcm數(shù)據(jù)傳入到下面這個方法中進(jìn)行AAC編碼闰围。
/**
* 編碼,得到{@link #encodeType}格式的音頻文件既峡,并保存到{@link #dstPath}
* @param data
*/
public void encodeData(byte[] data){
//dequeueInputBuffer(time)需要傳入一個時間值羡榴,-1表示一直等待,0表示不等待有可能會丟幀涧狮,其他表示等待多少毫秒
int inputIndex = mediaEncode.dequeueInputBuffer(-1);//獲取輸入緩存的index
if (inputIndex >= 0) {
ByteBuffer inputByteBuf = encodeInputBuffers[inputIndex];
inputByteBuf.clear();
inputByteBuf.put(data);//添加數(shù)據(jù)
inputByteBuf.limit(data.length);//限制ByteBuffer的訪問長度
mediaEncode.queueInputBuffer(inputIndex, 0, data.length, 0, 0);//把輸入緩存塞回去給MediaCodec
}
int outputIndex = mediaEncode.dequeueOutputBuffer(encodeBufferInfo, 0);//獲取輸出緩存的index
while (outputIndex >= 0) {
//獲取緩存信息的長度
int byteBufSize = encodeBufferInfo.size;
//添加ADTS頭部后的長度
int bytePacketSize = byteBufSize + 7;
//拿到輸出Buffer
ByteBuffer outPutBuf = encodeOutputBuffers[outputIndex];
outPutBuf.position(encodeBufferInfo.offset);
outPutBuf.limit(encodeBufferInfo.offset+encodeBufferInfo.size);
byte[] targetByte = new byte[bytePacketSize];
//添加ADTS頭部
addADTStoPacket(targetByte, bytePacketSize);
/*
get(byte[] dst,int offset,int length):ByteBuffer從position位置開始讀炕矮,讀取length個byte,并寫入dst下
標(biāo)從offset到offset + length的區(qū)域
*/
outPutBuf.get(targetByte,7,byteBufSize);
outPutBuf.position(encodeBufferInfo.offset);
try {
bos.write(targetByte);
} catch (IOException e) {
e.printStackTrace();
}
//釋放
mediaEncode.releaseOutputBuffer(outputIndex,false);
outputIndex = mediaEncode.dequeueOutputBuffer(encodeBufferInfo, 0);
}
}
如果是錄制過程中者冤,可以使用
audioRecord.read(audiodata, 0, bufferSizeInBytes);
方法拉取pcm數(shù)據(jù),把數(shù)據(jù)傳入到編碼方法中档痪,可以一邊錄制一邊編碼涉枫。
如果是已經(jīng)錄制好的pcm文件,同樣可以把文件轉(zhuǎn)換成流數(shù)據(jù)腐螟,再編碼愿汰。
/**
* 開始編碼
* PCM數(shù)據(jù)在編碼成想要得到的{@link #encodeType}音頻格式
* PCM->aac
*/
public void startAsync() {
Log.i(TAG, "start");
new Thread(new Runnable() {
@Override
public void run() {
try {
File file = new File(srcPath);
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
encodeData(bos.toByteArray());
bos.reset();
}
fis.close();
bos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
最后可以在目標(biāo)路徑下得到一個編碼格式為aac的文件,可以直接播放乐纸。
如果我們想把m4a衬廷,mp3的文件,進(jìn)行aac編碼汽绢。那就需要進(jìn)行轉(zhuǎn)碼吗跋,我們需要先對其進(jìn)行解碼成pcm數(shù)據(jù),再進(jìn)行編碼宁昭。后面我會在《Android 音視頻之音頻編碼轉(zhuǎn)換》中簡單介紹跌宛。
未完待更新...
上一篇:《Android 音視頻之音頻編碼》
下一篇:《Android 音視頻之音頻編碼轉(zhuǎn)換》
有問題的地方請大家?guī)兔χ赋觯x謝积仗。
持續(xù)更新中...