AAC介紹
介紹
AAC,全稱Advanced Audio Coding,是一種專為聲音數(shù)據(jù)設(shè)計(jì)的文件壓縮格式。他的目的是為了取代MP3格式,與MP3不同,它采用了全新的算法進(jìn)行編碼,更加高效,具有更高的“性價(jià)比”。利用AAC格式,可使人感覺(jué)聲音質(zhì)量沒(méi)有明顯降低的前提下,更加小巧。
為什么重點(diǎn)介紹AAC
1.他的應(yīng)用范圍廣。目前市場(chǎng)上泛娛樂(lè)化直播系統(tǒng),90%以上都是采用AAC編碼
2.目前的傳輸協(xié)議,一般采用rtmp協(xié)議,此協(xié)議支持aac,但是不支持OPUS??(因?yàn)镺PUS是最近才推出的,雖然強(qiáng),但是還不通用)
3.AAC本身編解碼器質(zhì)量非常高。作為一種高壓縮比的音頻壓縮算法,AAC通常壓縮比為18:1??(也有資料說(shuō)為20:1),但是還能保存較好的音質(zhì)。
AAC音頻格式
ADIF (Audio Data Interchange Format)
這種格式只需要在文件開頭存一個(gè)很小的頭,包括采樣率,采樣大小,聲道數(shù)量等基本信息,就可以對(duì)文件進(jìn)行解讀。這種格式只能從頭開始解碼,常用在磁盤文件中。
ADTS (Audio Data transport Stream)
這種格式每一幀前面都有一個(gè)同步字,占用7-9個(gè)字節(jié),好處是可以在音頻流的任何位置開始解碼,他類似于數(shù)據(jù)流格式。因?yàn)槊恳粠懊娑加型阶?,所以ADTS文件要比ADIF增加一些數(shù)據(jù)量
AAC產(chǎn)生原因
AAC產(chǎn)生目的就是為了取代MP3。
AAC之前,大部分音頻都還是使用MP3格式。MP3的使用規(guī)范是MPEG-2,他對(duì)于音頻編解碼,主要思想還是有損壓縮。有損壓縮在《Android 音視頻之音頻入門講解》也介紹過(guò),被壓縮的數(shù)據(jù)不能完全還原回來(lái),所以音質(zhì)上會(huì)有一定損耗。而且在碼率比較高的情況下,壓縮比要非常高的情況下,損耗性會(huì)非常大。AAC恰巧彌補(bǔ)了這個(gè)問(wèn)題,AAC對(duì)原始數(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次,他就可以完整記錄下模擬聲波,但是我們沒(méi)必要進(jìn)行這么多的采樣。高頻的20khz,我們采用44.1khz的采樣率,結(jié)果只采樣2次,這樣保真性就很差。而采用了SBR技術(shù),SBR把頻譜切割開來(lái),低頻單獨(dú)編碼保存主要成分, 高頻單獨(dú)放大編碼保存音質(zhì),這樣高頻就增加了采樣。這樣的好處,一是減少了碼率,二是提高了音頻的質(zhì)量。
AAC HE V2 : AAC + SBR + PS
PS(Parametric Stereo)是雙聲道分別保存,一個(gè)聲道完整保存,另一個(gè)只存差異的,參數(shù)的部分。因?yàn)閮蓚€(gè)聲道相關(guān)性非常強(qiáng),我們可以通過(guò)某種函數(shù),完全恢復(fù)以前的聲音?;谶@些原因,所以他只要存一些參數(shù)就可以了。

AAC優(yōu)點(diǎn)
①提升的壓縮率:可以以更小的文件大小獲得更高的音質(zhì);
②支持多聲道:可提供最多48個(gè)全音域聲道;
③更高的解析度:最高支持96KHz的采樣頻率;
④提升的解碼效率:解碼播放所占的資源更少;
AAC編解碼庫(kù)
Libfdk_AAC > ffmpeg AAC > libaac > libvo_aacenc
AAC編碼使用
使用ffmpeg對(duì)音頻進(jìn)行AAC編碼
不好意思,前段時(shí)間想采用ffmpeg去對(duì)AAC進(jìn)行編碼,結(jié)果開發(fā)過(guò)程中,發(fā)現(xiàn)ffmpeg avcodec_encode_audio2返回-22,導(dǎo)致編碼不成功,一直找不到原因。后期修改好了,我一定在文章和項(xiàng)目中補(bǔ)上。
使用MediaCodec對(duì)音頻進(jìn)行AAC硬編碼
????????Android中可以使用MediaCodec來(lái)訪問(wèn)底層的媒體編解碼器,可以對(duì)媒體進(jìn)行編/解碼。
????????舉例,比如之前文章《Android 音視頻之音頻錄制》,我們使用AudioRecord錄制了一個(gè)pcm文件。我們要將文件數(shù)據(jù)進(jìn)行AAC編碼,需要先初始化一個(gè)MediaCodec對(duì)象,設(shè)置他的MediaFormat為MediaFormat.MIMETYPE_AUDIO_AAC。如果想使用其他壓縮編碼,類似。代碼如下:
/**
* 初始化AAC編碼器
*/
private void initAACMediaEncode() {
try {
//參數(shù)對(duì)應(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ù)傳入到下面這個(gè)方法中進(jìn)行AAC編碼。
/**
* 編碼,得到{@link #encodeType}格式的音頻文件,并保存到{@link #dstPath}
* @param data
*/
public void encodeData(byte[] data){
//dequeueInputBuffer(time)需要傳入一個(gè)時(shí)間值,-1表示一直等待,0表示不等待有可能會(huì)丟幀,其他表示等待多少毫秒
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的訪問(wèn)長(zhǎng)度
mediaEncode.queueInputBuffer(inputIndex, 0, data.length, 0, 0);//把輸入緩存塞回去給MediaCodec
}
int outputIndex = mediaEncode.dequeueOutputBuffer(encodeBufferInfo, 0);//獲取輸出緩存的index
while (outputIndex >= 0) {
//獲取緩存信息的長(zhǎng)度
int byteBufSize = encodeBufferInfo.size;
//添加ADTS頭部后的長(zhǎng)度
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個(gè)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);
}
}
如果是錄制過(guò)程中,可以使用
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)路徑下得到一個(gè)編碼格式為aac的文件,可以直接播放。
如果我們想把m4a,mp3的文件,進(jìn)行aac編碼。那就需要進(jìn)行轉(zhuǎn)碼,我們需要先對(duì)其進(jìn)行解碼成pcm數(shù)據(jù),再進(jìn)行編碼。后面我會(huì)在《Android 音視頻之音頻編碼轉(zhuǎn)換》中簡(jiǎn)單介紹。
未完待更新...
上一篇:《Android 音視頻之音頻編碼》
下一篇:《Android 音視頻之音頻編碼轉(zhuǎn)換》
有問(wèn)題的地方請(qǐng)大家?guī)兔χ赋觯x謝。
持續(xù)更新中...