Foreword:
Here is the real-time stream AAC Audio decoding, the audio storage format is the byte stream saved by byte[].
1. Initialization of AudioTrack
private AudioTrack mAudioTrack = null;
int channelConfig = 2;
int audioFormat = 2;
int mMinBufSize = 0;
channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
audioFormat = AudioFormat.ENCODING_PCM_16BIT;
mMinBufSize = AudioTrack.getMinBufferSize(8000, channelConfig, audioFormat);
try {
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, channelConfig, AudioFormat
.ENCODING_PCM_16BIT, mMinBufSize, AudioTrack.MODE_STREAM);
} catch (IllegalArgumentException iae) {
iae.printStackTrace();
}
mAudioTrack.setStereoVolume(1.0f, 1.0f);
mAudioTrack.play();
After AudioTrack is initialized, MediaCodec is ready to be initialized. After using, remember to release AudioTrack
if (mAudioTrack != null) {
mAudioTrack.stop();
mAudioTrack.release();
mAudioTrack = null;
}
2. Initialize MediaCodec
Declaration of variables and constants
//声道数
private static final int KEY_CHANNEL_COUNT = 2;
//采样率
private static final int KEY_SAMPLE_RATE = 8000;
//解码器
public MediaCodec mediaCodec = null;
private ByteBuffer[] inputBuffers;
private ByteBuffer[] outputBuffers;
private MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
private int inIndex;
private int outIndex;
private String MINE = "audio/mp4a-latm";
private void prepare() {
try {
//需要解码数据的类型
//初始化解码器
mediaCodec = MediaCodec.createDecoderByType(MINE);
//MediaFormat用于描述音视频数据的相关参数
MediaFormat mediaFormat = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, KEY_SAMPLE_RATE, KEY_CHANNEL_COUNT);
//数据类型
mediaFormat.setString(MediaFormat.KEY_MIME, MINE);
//声道个数
mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2);
//采样率
mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, KEY_SAMPLE_RATE);
//比特率
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 128000);
// //用来标记AAC是否有adts头,1->有
mediaFormat.setInteger(MediaFormat.KEY_IS_ADTS, 1);
// //用来标记aac的类型
mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
// //ByteBuffer key
byte[] data = new byte[]{(byte) 0x15,(byte) 0x90};
ByteBuffer csd_0 = ByteBuffer.wrap(data);
mediaFormat.setByteBuffer("csd-0", csd_0);
//解码器配置
mediaCodec.configure(mediaFormat, null, null, 0);
} catch (IOException e) {
Log.e(TAG, " error:" + e.toString());
}
mediaCodec.start();
Log.i(TAG, "start mediacodec success");
inputBuffers = mediaCodec.getInputBuffers();
outputBuffers = mediaCodec.getOutputBuffers();
bufferInfo = new MediaCodec.BufferInfo();
}
Initialization of byte data[]:
AAC Profile 5bits | Sampling rate 4bits | Number of channels 4bits | Other 3bits |
AAC Profile (If it is other formats, please check the format code by yourself )
AAC Main 0x01
AAC LC 0x02
AAC SSR 0x03
Sampling rate encoding
0x00 96000
0x01 88200
0x02 64000
0x03 48000
0x04 44100
0x05 32000
0x06 24000
0x07 22050
0x08 16000
0x09 12000
0x0A 11025
0x0B 8000
0x0C reserved
0x0D reserved
0x0E reserved
0x0F escape value
Channel KEY_CHANNEL_COUNT encoding
0x00 - defined in audioDecderSpecificConfig
0x01 单声道(center front speaker)
0x02 双声道(left, right front speakers)
0x03 三声道(center, left, right front speakers)
0x04 四声道(center, left, right front speakers, rear surround speakers)
0x05 五声道(center, left, right front speakers, left surround, right surround rear speakers)
0x06 5.1声道(center, left, right front speakers, left surround, right surround rear speakers, front low frequency effects speaker)
0x07 7.1声道(center, left, right center front speakers, left, right outside front speakers, left surround, right surround rear speakers, front low frequency effects speaker)
0x08-0x0F - reserved
My audio format here is: AAC LC, sampling rate is 8000, number of channels is 2, other parameters are not, the default is 0
so the encoding format here is: 0x02,0x0b,0x02,0x00; converted to binary is: 00010 (5bits )1011(4bits)0010(4bits)000(3bits)
So,
data[] = new byte[]{(byte) 0x15, (byte) 0x90};
ByteBuffer csd_0 = ByteBuffer.wrap(data);
mediaFormat.setByteBuffer("csd-0", csd_0);
Add into the audio stream through MediaFormat setByteBuffer, and identify your decoding configuration parameters through this group of codes when decoding.
3.input buffer和output buffer
inputBuffers = mediaCodec.getInputBuffers();
outputBuffers = mediaCodec.getOutputBuffers();
bufferInfo = new MediaCodec.BufferInfo();
public void input(byte[] frameData) {
//这里注释的代码是给AAC音频流添加ADTS头部的,我们的数据流中已经有了头,所以注释了,这里不删除,留给有需要的人
/*byte[] ADTS = new byte[7];
addADTStoPacket(ADTS, frameData.length + 7);
byte[] frameDataAddADTS = new byte[frameData.length];
System.arraycopy(ADTS, 0, frameDataAddADTS, 0, 7);
System.arraycopy(frameData, 0, frameDataAddADTS, 0, frameData.length);*/
ByteBuffer inputBuffer = null;
//API>=21区分
// 1.-1表示一直等待 2.0表示不等待 3.大于0表示等待的时间(us)
inIndex = mediaCodec.dequeueInputBuffer(-1);
Log.e("lvyouhai","inIndex:" + inIndex);
if (inIndex >= 0) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
inputBuffer = mediaCodec.getInputBuffer(inIndex);
} else {
inputBuffer = inputBuffers[inIndex];
}
inputBuffer.clear();
inputBuffer.put(frameData, 0, frameData.length);
mediaCodec.queueInputBuffer(inIndex, 0, frameData.length, 0, 0);
inIndex = mediaCodec.dequeueInputBuffer(0);
}
}
public byte[] output() {
ByteBuffer outputBuffer = null;
byte[] getBuffer = null;
outIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 5000);
while (outIndex >= 0) {
getBuffer = new byte[bufferInfo.size];
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
outputBuffer = mediaCodec.getOutputBuffer(outIndex);
} else {
outputBuffer = outputBuffers[outIndex];
}
outputBuffer.get(getBuffer);
outputBuffer.position(0);
outputBuffer.limit(bufferInfo.size);
outputBuffer.clear();
mediaCodec.releaseOutputBuffer(outIndex, false);
outIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 5000);
}
return getBuffer;
}
private byte[] addADTStoPacket(byte[] packet, int packetLen) {
int profile = 2; // AAC LC
int freqIdx = 4; // 44.1KHz
int chanCfg = 2; // CPE
// fill in ADTS data
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;
return packet;
}
Remember to release the MediaCodec resource after decoding, if it is a real-time stream, decide according to the execution order of your own code
public void stop() {
Log.e(TAG, "stop MediaCodec and release");
if (mediaCodec != null) {
mediaCodec.stop();
mediaCodec.release();
}
mediaCodec = null;
}
4. Play
Here, receiveBuffer is the AAC byte[] byte stream that needs to be decoded.
mediaCodecDecAudio.input(receiveBuffer);
byte[] outputAudioBuffer = null;
outputAudioBuffer = mediaCodecDecAudio.output();
if(outputAudioBuffer == null) {
//do nothing
}else {
try {
mAudioTrack.write(outputAudioBuffer, 0, (int)outputAudioBuffer.length);
}catch (IndexOutOfBoundsException e){
e.getStackTrace();
}
}
PS:
Possible problems:
AAC decoding here only encounters one problem, that is, the decoded data is blank. Later, after continuous printing of logs, it is found that there is a problem with the configuration parameters of MediaFormat. There is no specific explanation here, because the decoded data The configuration needs to be changed slightly. The more important parameter is
(1) Whether the data stream is ADTS or not, it needs to be judged by printing the decoded byte stream
MediaFormat.KEY_IS_ADTS
(2) Adding data data, which is an important parameter for manual configuration of decoding and recognition. If something goes wrong, there will be many problems with decoding data.
byte[] data
I haven't encountered other problems yet, and I hope you can communicate with you when you encounter other AAC hard decoding problems.