在Android上使用AudioRecord和MediaCodec对AAC Audio进行编码

前端之家收集整理的这篇文章主要介绍了在Android上使用AudioRecord和MediaCodec对AAC Audio进行编码前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我试图使用 android AudioRecord和MediaCodec来编码aac音频.我创建了一个非常类似于( Encoding H.264 from camera with Android MediaCodec)的编码器类.使用这个类,我创建了一个AudioRecord的实例,并告诉它将其byte []数据读取到AudioEncoder(audioEncoder.offerEncoder(Data)).
  1. while(isRecording)
  2. {
  3. audioRecord.read(Data,Data.length);
  4. audioEncoder.offerEncoder(Data);
  5. }

这是我的AudioRecord设置

  1. int audioSource = MediaRecorder.AudioSource.MIC;
  2. int sampleRateInHz = 44100;
  3. int channelConfig = AudioFormat.CHANNEL_IN_MONO;
  4. int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
  5. 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甚至不会写输出音频文件.
有什么我错过的吗?我的设置是否正确?

欢迎任何建议,意见和意见,非常感谢.多谢你们!

  1. import android.media.MediaCodec;
  2. import android.media.MediaCodecInfo;
  3. import android.media.MediaFormat;
  4. import android.os.Environment;
  5. import android.util.Log;
  6.  
  7. import java.io.BufferedOutputStream;
  8. import java.io.File;
  9. import java.io.FileOutputStream;
  10. import java.io.IOException;
  11. import java.nio.ByteBuffer;
  12.  
  13. public class AudioEncoder {
  14.  
  15. private MediaCodec mediaCodec;
  16. private BufferedOutputStream outputStream;
  17. private String mediaType = "audio/mp4a-latm";
  18.  
  19. public AudioEncoder() {
  20. File f = new File(Environment.getExternalStorageDirectory(),"Download/audio_encoded.aac");
  21. touch(f);
  22. try {
  23. outputStream = new BufferedOutputStream(new FileOutputStream(f));
  24. Log.e("AudioEncoder","outputStream initialized");
  25. } catch (Exception e){
  26. e.printStackTrace();
  27. }
  28.  
  29. mediaCodec = MediaCodec.createEncoderByType(mediaType);
  30. final int kSampleRates[] = { 8000,11025,22050,44100,48000 };
  31. final int kBitRates[] = { 64000,128000 };
  32. MediaFormat mediaFormat = MediaFormat.createAudioFormat(mediaType,kSampleRates[3],1);
  33. mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE,MediaCodecInfo.CodecProfileLevel.AACObjectLC);
  34.  
  35. mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE,kBitRates[1]);
  36. mediaCodec.configure(mediaFormat,null,MediaCodec.CONFIGURE_FLAG_ENCODE);
  37. mediaCodec.start();
  38. }
  39.  
  40. public void close() {
  41. try {
  42. mediaCodec.stop();
  43. mediaCodec.release();
  44. outputStream.flush();
  45. outputStream.close();
  46. } catch (Exception e){
  47. e.printStackTrace();
  48. }
  49. }
  50.  
  51. // called AudioRecord's read
  52. public synchronized void offerEncoder(byte[] input) {
  53. Log.e("AudioEncoder",input.length + " is coming");
  54.  
  55. try {
  56. ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
  57. ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
  58. int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
  59. if (inputBufferIndex >= 0) {
  60. ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
  61. inputBuffer.clear();
  62.  
  63. inputBuffer.put(input);
  64.  
  65.  
  66. mediaCodec.queueInputBuffer(inputBufferIndex,input.length,0);
  67. }
  68.  
  69. MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
  70. int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);
  71.  
  72. ////trying to add a ADTS
  73. // while (outputBufferIndex >= 0) {
  74. // int outBitsSize = bufferInfo.size;
  75. // int outPacketSize = outBitsSize + 7; // 7 is ADTS size
  76. // ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
  77. //
  78. // outputBuffer.position(bufferInfo.offset);
  79. // outputBuffer.limit(bufferInfo.offset + outBitsSize);
  80. //
  81. // byte[] outData = new byte[outPacketSize];
  82. // addADTStoPacket(outData,outPacketSize);
  83. //
  84. // outputBuffer.get(outData,7,outBitsSize);
  85. // outputBuffer.position(bufferInfo.offset);
  86. //
  87. //// byte[] outData = new byte[bufferInfo.size];
  88. // outputStream.write(outData,outData.length);
  89. // Log.e("AudioEncoder",outData.length + " bytes written");
  90. //
  91. // mediaCodec.releaSEOutputBuffer(outputBufferIndex,false);
  92. // outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);
  93. //
  94. // }
  95.  
  96.  
  97. //Without ADTS header
  98. while (outputBufferIndex >= 0) {
  99. ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
  100. byte[] outData = new byte[bufferInfo.size];
  101. outputBuffer.get(outData);
  102. outputStream.write(outData,outData.length);
  103. Log.e("AudioEncoder",outData.length + " bytes written");
  104.  
  105. mediaCodec.releaSEOutputBuffer(outputBufferIndex,false);
  106. outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);
  107.  
  108. }
  109. } catch (Throwable t) {
  110. t.printStackTrace();
  111. }
  112.  
  113. }
  114.  
  115. /**
  116. * Add ADTS header at the beginning of each and every AAC packet.
  117. * This is needed as MediaCodec encoder generates a packet of raw
  118. * AAC data.
  119. *
  120. * Note the packetLen must count in the ADTS header itself.
  121. **/
  122. private void addADTStoPacket(byte[] packet,int packetLen) {
  123. int profile = 2; //AAC LC
  124. //39=MediaCodecInfo.CodecProfileLevel.AACObjectELD;
  125. int freqIdx = 4; //44.1KHz
  126. int chanCfg = 2; //CPE
  127.  
  128. // fill in ADTS data
  129. packet[0] = (byte)0xFF;
  130. packet[1] = (byte)0xF9;
  131. packet[2] = (byte)(((profile-1)<<6) + (freqIdx<<2) +(chanCfg>>2));
  132. packet[3] = (byte)(((chanCfg&3)<<6) + (packetLen>>11));
  133. packet[4] = (byte)((packetLen&0x7FF) >> 3);
  134. packet[5] = (byte)(((packetLen&7)<<5) + 0x1F);
  135. packet[6] = (byte)0xFC;
  136. }
  137.  
  138. public void touch(File f)
  139. {
  140. try {
  141. if(!f.exists())
  142. f.createNewFile();
  143. } catch (IOException e) {
  144. e.printStackTrace();
  145. }
  146. }
  147. }

解决方法

您可以使用Android的 MediaMuxer将MediaCodec创建的原始流打包成.mp4文件.奖金:包含在.mp4中的AAC数据包不需要ADTS头.

我有一个working example of this technique on Github.

猜你在找的Android相关文章