MediaCodec
是Android(api>=16)
提供的一个多媒体硬解编码库,能实现音视频的编解码。
工作原理:其内部有2个队列,一个是输入队列,一个是输出队列。输入队列负责存储编
解码前的原始数据存储,并输送给MediaCodec
处理;输出队列负责存储编解码后
的新数据,可以直接处理或保存到文件中。
AAC
的头部信息介绍 :https://blog.csdn.net/jay100500/article/details/52955232
//mediacodec
private MediaFormat encoderFormat = null;
private MediaCodec encoder = null;
private FileOutputStream outputStream = null;
private MediaCodec.BufferInfo info = null;
private int perpcmsize = 0;
private byte[] outByteBuffer = null;
private int aacsamplerate = 4;
private double recordTime = 0;
private int audioSamplerate = 0;
private void initMediacodec(int samperate, File outfile)
{
try {
aacsamplerate = getADTSsamplerate(samperate);
//立体声
encoderFormat = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, samperate, 2);
//96kbps fm音质
encoderFormat.setInteger(MediaFormat.KEY_BIT_RATE, 96000);
encoderFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
encoderFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 4096);
encoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
info = new MediaCodec.BufferInfo();
if(encoder == null)
{
MyLog.d("craete encoder wrong");
return;
}
recordTime = 0;
encoder.configure(encoderFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
outputStream = new FileOutputStream(outfile);
encoder.start();
} catch (IOException e) {
e.printStackTrace();
}
}
private void encodecPcmToAAc(int size, byte[] buffer)
{
if(buffer != null && encoder != null)
{
//录音时间 size/ 采样率*声道数 * bits/8
recordTime += size * 1.0 / (audioSamplerate * 2 * (16 / 8));
MyLog.d("recordTime = " + recordTime);
//回掉
if(wlOnRecordTimeListener != null)
{
wlOnRecordTimeListener.onRecordTime((int) recordTime);
}
int inputBufferindex = encoder.dequeueInputBuffer(0);
if(inputBufferindex >= 0)
{
ByteBuffer byteBuffer = encoder.getInputBuffers()[inputBufferindex];
byteBuffer.clear();
byteBuffer.put(buffer);
encoder.queueInputBuffer(inputBufferindex, 0, size, 0, 0);
}
int index = encoder.dequeueOutputBuffer(info, 0);
while(index >= 0)
{
try {
perpcmsize = info.size + 7;
outByteBuffer = new byte[perpcmsize];
ByteBuffer byteBuffer = encoder.getOutputBuffers()[index];
byteBuffer.position(info.offset);
byteBuffer.limit(info.offset + info.size);
addADtsHeader(outByteBuffer, perpcmsize, aacsamplerate);
byteBuffer.get(outByteBuffer, 7, info.size);
byteBuffer.position(info.offset);
outputStream.write(outByteBuffer, 0, perpcmsize);
encoder.releaseOutputBuffer(index, false);
index = encoder.dequeueOutputBuffer(info, 0);
outByteBuffer = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void addADtsHeader(byte[] packet, int packetLen, int samplerate)
{
int profile = 2; // AAC LC
int freqIdx = samplerate; // samplerate
int chanCfg = 2; // CPE
packet[0] = (byte) 0xFF; // 0xFFF(12bit) 这里只取了8位,所以还差4位放到下一个里面
packet[1] = (byte) 0xF9; // 第一个t位放F
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;
}
private int getADTSsamplerate(int samplerate)
{
int rate = 4;
switch (samplerate)
{
case 96000:
rate = 0;
break;
case 88200:
rate = 1;
break;
case 64000:
rate = 2;
break;
case 48000:
rate = 3;
break;
case 44100:
rate = 4;
break;
case 32000:
rate = 5;
break;
case 24000:
rate = 6;
break;
case 22050:
rate = 7;
break;
case 16000:
rate = 8;
break;
case 12000:
rate = 9;
break;
case 11025:
rate = 10;
break;
case 8000:
rate = 11;
break;
case 7350:
rate = 12;
break;
}
return rate;
}
private void releaseMedicacodec()
{
if(encoder == null)
{
return;
}
try {
recordTime = 0;
outputStream.close();
outputStream = null;
encoder.stop();
encoder.release();
encoder = null;
encoderFormat = null;
info = null;
initmediacodec = false;
MyLog.d("录制完成...");
} catch (IOException e) {
e.printStackTrace();
}
finally {
if(outputStream != null)
{
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
outputStream = null;
}
}
}