使用AudioRecord采样回来的float数组如何编码成aac?
audioFormat 设置成 AudioFormat.ENCODING_PCM_FLOAT,read之后是float数组。而MediaCodec编码需要的是byte数组,如何使用MediaCodec正确编码成aac文件?使用了ByteBuffer putFloat(int index, float value) 之后发现音频文件时长变成了真实时长的好几倍。不知道具体哪里出了问题
初始化
int audioSource = MediaRecorder.AudioSource.MIC;
int channelConfig = AudioFormat.CHANNEL_IN_MONO;//单声道
int channelCount = 1;//对应的通道数
int audioFormat = AudioFormat.ENCODING_PCM_FLOAT;//采样位数
int sampleRate = 48000;//采样率
int bitRate = sampleRate * channelCount * 32;//【比特率】= 【采样率】* 【通道】* 【采样位数】
int sampleSize = sampleRate / (1000 / 25);//每次采样的样本个数 1000 / 25 => 每25ms采样一次 1秒采样40次 即每次获取12000个样本
// int bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
int bufferSizeInBytes = sampleSize * 4;//float * 4
floatBuffer = new float[sampleSize];
audioRecorder = new AudioRecord(audioSource, sampleRate, channelConfig, audioFormat, bufferSizeInBytes);
//初始化编码器
mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
MediaFormat mediaFormat = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, sampleRate, channelCount);
mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);//标记aac级别
mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, bufferSizeInBytes);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
bufferInfo = new MediaCodec.BufferInfo();
读取录音
try {
long nanoTime = System.nanoTime() / 1000;
while (isRecording) {
//获取音频
int len = audioRecorder.read(floatBuffer, 0, floatBuffer.length, AudioRecord.READ_BLOCKING);
if (len > 0) {
ByteBuffer inputBuffer = null;
int inputIndex = mediaCodec.dequeueInputBuffer(-1);
if (inputIndex >= 0) {
inputBuffer = mediaCodec.getInputBuffer(inputIndex);
inputBuffer.clear();
}
for (int i = 0; i < len; i++) {
int intBits = Float.floatToIntBits(floatBuffer[i]);
// 把float数据塞入ByteBuffer
if (inputBuffer != null) {
inputBuffer.putFloat(i, floatBuffer[i]);
}
}
//编码48000-32bit的采样数据
if (inputBuffer != null) {
mediaCodec.queueInputBuffer(inputIndex, 0, len * 4, nanoTime, 0);
nanoTime += 25000;//增加25毫秒
}
}
}
} catch (Exception e) {
Log.d(TAG, "record出错:" + e);
}
另外一个线程:获取编码后的数据,并写入文件
File outputFile = new File(audioRecordFilePath);
if (!outputFile.getParentFile().exists()) {
outputFile.getParentFile().mkdirs();
}
FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
while (isRecording) {
//获取编码后的数据
int outputIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
while (outputIndex >= 0 && isRecording) {
ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputIndex);//拿到输出Buffer
outputBuffer.position(bufferInfo.offset);
byte[] outData = new byte[bufferInfo.size + 7];
outputBuffer.get(outData, 7, bufferInfo.size);//将编码得到的AAC数据 取出到byte[]中
addADTStoPacket(outData, outData.length);
fileOutputStream.write(outData);
//再取一遍
mediaCodec.releaseOutputBuffer(outputIndex, false);
outputIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
}
fileOutputStream.flush();
fileOutputStream.close();
AAC裸流添加ADTS头
private static final int AAC_PROFILE = 2;//AAC LC,MediaCodecInfo.CodecProfileLevel.AACObjectLC
private static final int AAC_CHANNEL_CONFIG = 1;//单声道
private static final int AAC_FREQ_IDX = 8;//对应的是48000采样率
private void addADTStoPacket(byte[] packet, int packetLen) {
packet[0] = (byte) 0xFF;
packet[1] = (byte) 0xF9;
packet[2] = (byte) (((AAC_PROFILE - 1) << 6) + (AAC_FREQ_IDX << 2) + (AAC_CHANNEL_CONFIG >> 2));
packet[3] = (byte) (((AAC_CHANNEL_CONFIG & 3) << 6) + (packetLen >> 11));
packet[4] = (byte) ((packetLen & 0x7FF) >> 3);
packet[5] = (byte) (((packetLen & 7) << 5) + 0x1F);
packet[6] = (byte) 0xFC;
}