我试图使用
android AudioRecord和MediaCodec来编码aac音频.我创建了一个非常类似于(
Encoding H.264 from camera with Android MediaCodec)的编码器类.使用这个类,我创建了一个AudioRecord的实例,并告诉它将其byte []数据读取到AudioEncoder(audioEncoder.offerEncoder(Data)).
while(isRecording) { audioRecord.read(Data,Data.length); audioEncoder.offerEncoder(Data); }
这是我的AudioRecord设置
int audioSource = MediaRecorder.AudioSource.MIC; int sampleRateInHz = 44100; int channelConfig = AudioFormat.CHANNEL_IN_MONO; int audioFormat = AudioFormat.ENCODING_PCM_16BIT; int bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz,channelConfig,audioFormat);
我成功收集了一些byte []数组数据并将其写入本地文件.不幸的是,该文件不可播放.我在网上进行了一些搜索,并发现了一个相关的帖子(How to generate the AAC ADTS elementary stream with Android MediaCodec).所以有同样问题的人说主要的问题是“MediaCodec编码器生成原始的AAC流,原始的AAC流需要被转换成可播放的格式,如ADTS流”.所以我试图添加ADTS标题.然而,在添加了ADTS标题(我在下面的代码中注释掉)后,我的AudioEncoder甚至不会写输出音频文件.
有什么我错过的吗?我的设置是否正确?
欢迎任何建议,意见和意见,非常感谢.多谢你们!
import android.media.MediaCodec; import android.media.MediaCodecInfo; import android.media.MediaFormat; import android.os.Environment; import android.util.Log; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; public class AudioEncoder { private MediaCodec mediaCodec; private BufferedOutputStream outputStream; private String mediaType = "audio/mp4a-latm"; public AudioEncoder() { File f = new File(Environment.getExternalStorageDirectory(),"Download/audio_encoded.aac"); touch(f); try { outputStream = new BufferedOutputStream(new FileOutputStream(f)); Log.e("AudioEncoder","outputStream initialized"); } catch (Exception e){ e.printStackTrace(); } mediaCodec = MediaCodec.createEncoderByType(mediaType); final int kSampleRates[] = { 8000,11025,22050,44100,48000 }; final int kBitRates[] = { 64000,128000 }; MediaFormat mediaFormat = MediaFormat.createAudioFormat(mediaType,kSampleRates[3],1); mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE,MediaCodecInfo.CodecProfileLevel.AACObjectLC); mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE,kBitRates[1]); mediaCodec.configure(mediaFormat,null,MediaCodec.CONFIGURE_FLAG_ENCODE); mediaCodec.start(); } public void close() { try { mediaCodec.stop(); mediaCodec.release(); outputStream.flush(); outputStream.close(); } catch (Exception e){ e.printStackTrace(); } } // called AudioRecord's read public synchronized void offerEncoder(byte[] input) { Log.e("AudioEncoder",input.length + " is coming"); try { ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers(); ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers(); int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1); if (inputBufferIndex >= 0) { ByteBuffer inputBuffer = inputBuffers[inputBufferIndex]; inputBuffer.clear(); inputBuffer.put(input); mediaCodec.queueInputBuffer(inputBufferIndex,input.length,0); } MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0); ////trying to add a ADTS // while (outputBufferIndex >= 0) { // int outBitsSize = bufferInfo.size; // int outPacketSize = outBitsSize + 7; // 7 is ADTS size // ByteBuffer outputBuffer = outputBuffers[outputBufferIndex]; // // outputBuffer.position(bufferInfo.offset); // outputBuffer.limit(bufferInfo.offset + outBitsSize); // // byte[] outData = new byte[outPacketSize]; // addADTStoPacket(outData,outPacketSize); // // outputBuffer.get(outData,7,outBitsSize); // outputBuffer.position(bufferInfo.offset); // //// byte[] outData = new byte[bufferInfo.size]; // outputStream.write(outData,outData.length); // Log.e("AudioEncoder",outData.length + " bytes written"); // // mediaCodec.releaSEOutputBuffer(outputBufferIndex,false); // outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0); // // } //Without ADTS header while (outputBufferIndex >= 0) { ByteBuffer outputBuffer = outputBuffers[outputBufferIndex]; byte[] outData = new byte[bufferInfo.size]; outputBuffer.get(outData); outputStream.write(outData,outData.length); Log.e("AudioEncoder",outData.length + " bytes written"); mediaCodec.releaSEOutputBuffer(outputBufferIndex,false); outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0); } } catch (Throwable t) { t.printStackTrace(); } } /** * Add ADTS header at the beginning of each and every AAC packet. * This is needed as MediaCodec encoder generates a packet of raw * AAC data. * * Note the packetLen must count in the ADTS header itself. **/ private void addADTStoPacket(byte[] packet,int packetLen) { int profile = 2; //AAC LC //39=MediaCodecInfo.CodecProfileLevel.AACObjectELD; 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; } public void touch(File f) { try { if(!f.exists()) f.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } }
解决方法
您可以使用Android的
MediaMuxer将MediaCodec创建的原始流打包成.mp4文件.奖金:包含在.mp4中的AAC数据包不需要ADTS头.