AAC是音頻的一種編碼格式,AAC通常壓縮比為18:1,也有資料說為20:1,遠(yuǎn)勝mp3。
AAC音頻格式有ADIF和ADTS:
ADIF:Audio Data Interchange Format 音頻數(shù)據(jù)交換格式。這種格式的特征是可以確定的找到這個(gè)音頻數(shù)據(jù)的開始,不需進(jìn)行在音頻數(shù)據(jù)流中間開始的解碼,即它的解碼必須在明確定義的開始處進(jìn)行。故這種格式常用在磁盤文件中。
ADTS:Audio Data Transport Stream 音頻數(shù)據(jù)傳輸流。這種格式的特征是它是一個(gè)有同步字的比特流,解碼可以在這個(gè)流中任何位置開始。它的特征類似于mp3數(shù)據(jù)流格式。
簡單說,ADTS可以在任意幀解碼,也就是說它每一幀都有頭信息。ADIF只有一個(gè)統(tǒng)一的頭,所以必須得到所有的數(shù)據(jù)后解碼。且這兩種的header的格式也是不同的,目前一般編碼后的和抽取出的都是ADTS格式的音頻流。
ADTS是幀序列,本身具備流特征,在音頻流的傳輸與處理方面更加合適。
?
下面我們對(duì)ADTS進(jìn)行分析:
ADTS AAC | ||||||
---|---|---|---|---|---|---|
ADTS_header | AAC ES | ADTS_header | AAC ES | ... | ADTS_header | AAC ES |
可以看到ADTS的每一幀都有頭信息,即ADTS_header,ADTS頭中相對(duì)有用的信息是采樣率、聲道數(shù)、幀長度。一般ADTS頭信息都是7字節(jié),如果有CRC則為9字節(jié)。
ADTS幀首部結(jié)構(gòu):
序號(hào) | 域 | 長度(bits) | 說明 |
---|---|---|---|
1 | Syncword | 12 | all bits must be 1 |
2 | MPEG version | 1 | 0 for MPEG-4, 1 for MPEG-2 |
3 | Layer | 2 | always 0 |
4 | Protection Absent | 1 | et to 1 if there is no CRC and 0 if there is CRC |
5 | Profile | 2 | the MPEG-4 Audio Object Type minus 1 |
6 | MPEG-4 Sampling Frequency Index | 4 | MPEG-4 Sampling Frequency Index (15 is forbidden) |
7 | Private Stream | 1 | set to 0 when encoding, ignore when decoding |
8 | MPEG-4 Channel Configuration | 3 | MPEG-4 Channel Configuration (in the case of 0, the channel configuration is sent via an inband PCE) |
9 | Originality | 1 | set to 0 when encoding, ignore when decoding |
10 | Home | 1 | set to 0 when encoding, ignore when decoding |
11 | Copyrighted Stream | 1 | set to 0 when encoding, ignore when decoding |
12 | Copyrighted Start | 1 | set to 0 when encoding, ignore when decoding |
13 | Frame Length | 13 | this value must include 7 or 9 bytes of header length: FrameLength = (ProtectionAbsent == 1 ? 7 : 9) + size(AACFrame) |
14 | Buffer Fullness | 11 | buffer fullness |
15 | Number of AAC Frames | 2 | number of AAC frames (RDBs) in ADTS frame minus 1, for maximum compatibility always use 1 AAC frame per ADTS frame |
16 | CRC | 16 | CRC if protection absent is 0 |
?
ADTS頭部的生成:
/**
* 添加ADTS頭部
*
* @param packet ADTS header 的 byte[],長度為7
* @param packetLen 該幀的長度,包括header的長度
*/
private void addADTStoPacket(byte[] packet, int packetLen) {
int profile = 2; // AAC LC
int freqIdx = 3; // 48000Hz
int chanCfg = 2; // 2 Channel
packet[0] = (byte) 0xFF;
packet[1] = (byte) 0xF9;
packet[2] = (byte) (((profile - 1) << 6) + (freqIdx << 2) + (chanCfg >> 2));
packet[3] = (byte) (((chanCfg & 3) << 6) + (packetLen >> 11));
packet[4] = (byte) ((packetLen & 0x7FF) >> 3);
packet[5] = (byte) (((packetLen & 7) << 5) + 0x1F);
packet[6] = (byte) 0xFC;
}
其中profile表示使用哪個(gè)級(jí)別的AAC,在MPEG-2 AAC中定義了3種:
freqIdx表示使用的采樣率下標(biāo),通過這個(gè)下標(biāo)在 Sampling Frequencies[ ]數(shù)組中查找得知采樣率的值:
- 0: 96000 Hz
- 1: 88200 Hz
- 2: 64000 Hz
- 3: 48000 Hz
- 4: 44100 Hz
- 5: 32000 Hz
- 6: 24000 Hz
- 7: 22050 Hz
- 8: 16000 Hz
- 9: 12000 Hz
- 10: 11025 Hz
- 11: 8000 Hz
- 12: 7350 Hz
- 13: Reserved
- 14: Reserved
- 15: frequency is written explictly
chanCfg表示聲道數(shù):
- 0: Defined in AOT Specifc Config
- 1: 1 channel: front-center
- 2: 2 channels: front-left, front-right
- 3: 3 channels: front-center, front-left, front-right
- 4: 4 channels: front-center, front-left, front-right, back-center
- 5: 5 channels: front-center, front-left, front-right, back-left, back-right
- 6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
- 7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
- 8-15: Reserved
?
AAC的解析:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
public class AACHelper {
// 采樣頻率對(duì)照表
private static Map<Integer, Integer> samplingFrequencyIndexMap = new HashMap<>();
static {
samplingFrequencyIndexMap.put(96000, 0);
samplingFrequencyIndexMap.put(88200, 1);
samplingFrequencyIndexMap.put(64000, 2);
samplingFrequencyIndexMap.put(48000, 3);
samplingFrequencyIndexMap.put(44100, 4);
samplingFrequencyIndexMap.put(32000, 5);
samplingFrequencyIndexMap.put(24000, 6);
samplingFrequencyIndexMap.put(22050, 7);
samplingFrequencyIndexMap.put(16000, 8);
samplingFrequencyIndexMap.put(12000, 9);
samplingFrequencyIndexMap.put(11025, 10);
samplingFrequencyIndexMap.put(8000, 11);
samplingFrequencyIndexMap.put(0x0, 96000);
samplingFrequencyIndexMap.put(0x1, 88200);
samplingFrequencyIndexMap.put(0x2, 64000);
samplingFrequencyIndexMap.put(0x3, 48000);
samplingFrequencyIndexMap.put(0x4, 44100);
samplingFrequencyIndexMap.put(0x5, 32000);
samplingFrequencyIndexMap.put(0x6, 24000);
samplingFrequencyIndexMap.put(0x7, 22050);
samplingFrequencyIndexMap.put(0x8, 16000);
samplingFrequencyIndexMap.put(0x9, 12000);
samplingFrequencyIndexMap.put(0xa, 11025);
samplingFrequencyIndexMap.put(0xb, 8000);
}
private AdtsHeader mAdtsHeader = new AdtsHeader();
private BitReader mHeaderBitReader = new BitReader(new byte[7]);
private byte[] mSkipTwoBytes = new byte[2];
private FileInputStream mFileInputStream;
private byte[] mBytes = new byte[1024];
/**
* 構(gòu)造函數(shù),通過傳遞進(jìn)來的文件路徑創(chuàng)建輸入流
*
* @param aacFilePath AAC文件路徑
* @throws FileNotFoundException
*/
public AACHelper(String aacFilePath) throws FileNotFoundException {
mFileInputStream = new FileInputStream(aacFilePath);
}
/**
* 獲取下一Sample數(shù)據(jù)
*
* @param byteBuffer 存放Sample數(shù)據(jù)的ByteBuffer
* @return 當(dāng)前Sample的byte[]大小,如果為空返回-1
* @throws IOException
*/
public int getSample(ByteBuffer byteBuffer) throws IOException {
if (readADTSHeader(mAdtsHeader, mFileInputStream)) {
int length = mFileInputStream.read(mBytes, 0, mAdtsHeader.frameLength - mAdtsHeader.getSize());
byteBuffer.clear();
byteBuffer.put(mBytes, 0, length);
byteBuffer.position(0);
byteBuffer.limit(length);
return length;
}
return -1;
}
/**
* 從AAC文件流中讀取ADTS頭部
*
* @param adtsHeader ADTS頭部
* @param fileInputStream AAC文件流
* @return 是否讀取成功
* @throws IOException
*/
private boolean readADTSHeader(AdtsHeader adtsHeader, FileInputStream fileInputStream) throws IOException {
if (fileInputStream.read(mHeaderBitReader.buffer) < 7) {
return false;
}
mHeaderBitReader.position = 0;
int syncWord = mHeaderBitReader.readBits(12); // A
if (syncWord != 0xfff) {
throw new IOException("Expected Start Word 0xfff");
}
adtsHeader.mpegVersion = mHeaderBitReader.readBits(1); // B
adtsHeader.layer = mHeaderBitReader.readBits(2); // C
adtsHeader.protectionAbsent = mHeaderBitReader.readBits(1); // D
adtsHeader.profile = mHeaderBitReader.readBits(2) + 1; // E
adtsHeader.sampleFrequencyIndex = mHeaderBitReader.readBits(4);
adtsHeader.sampleRate = samplingFrequencyIndexMap.get(adtsHeader.sampleFrequencyIndex); // F
mHeaderBitReader.readBits(1); // G
adtsHeader.channelconfig = mHeaderBitReader.readBits(3); // H
adtsHeader.original = mHeaderBitReader.readBits(1); // I
adtsHeader.home = mHeaderBitReader.readBits(1); // J
adtsHeader.copyrightedStream = mHeaderBitReader.readBits(1); // K
adtsHeader.copyrightStart = mHeaderBitReader.readBits(1); // L
adtsHeader.frameLength = mHeaderBitReader.readBits(13); // M
adtsHeader.bufferFullness = mHeaderBitReader.readBits(11); // 54
adtsHeader.numAacFramesPerAdtsFrame = mHeaderBitReader.readBits(2) + 1; // 56
if (adtsHeader.numAacFramesPerAdtsFrame != 1) {
throw new IOException("This muxer can only work with 1 AAC frame per ADTS frame");
}
if (adtsHeader.protectionAbsent == 0) {
fileInputStream.read(mSkipTwoBytes);
}
return true;
}
/**
* 釋放資源
*
* @throws IOException
*/
public void release() throws IOException {
mFileInputStream.close();
}
/**
* ADTS頭部
*/
private class AdtsHeader {
int getSize() {
return 7 + (protectionAbsent == 0 ? 2 : 0);
}
int sampleFrequencyIndex;
int mpegVersion;
int layer;
int protectionAbsent;
int profile;
int sampleRate;
int channelconfig;
int original;
int home;
int copyrightedStream;
int copyrightStart;
int frameLength;
int bufferFullness;
int numAacFramesPerAdtsFrame;
}
}