Codificación de audio AAC utilizando AudioRecord y MediaCodec en Android

Estoy intentando codificar el audio del aac usando androide AudioRecord y MediaCodec. He creado una clase codificador muy similar a ( Codificación H.264 de la cámara con Android MediaCodec ). Con esta clase, he creado una instancia de AudioRecord y le digo que lea sus datos de byte [] a AudioEncoder (audioEncoder.offerEncoder (Data)).

while(isRecording) { audioRecord.read(Data, 0, Data.length); audioEncoder.offerEncoder(Data); } 

Aquí está mi configuración para mi 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); 

Recolecté con éxito algunos datos de la matriz del byte [] y lo escribí en un archivo local. Desafortunadamente, el archivo no es reproducible. Hice un poco más de búsqueda en línea y encontró un post relacionado ( Cómo generar el flujo de AAC ADTS elemental con Android MediaCodec ). Por lo tanto, otros que están teniendo problemas similares están diciendo que el principal problema es "El codificador de MediaCodec genera el flujo de AAC sin procesar. El flujo de AAC sin procesar necesita ser convertido en un formato reproducible, como el flujo de ADTS". Así que traté de añadir el encabezado ADTS. Sin embargo, después de agregar el encabezado ADTS (comenté en el código de abajo), mi AudioEncoder ni siquiera escribir el archivo de salida de audio. ¿Hay algo que me falta? ¿Mi configuración es correcta?

Cualquier sugerencia, comentario y opinión son bienvenidos y muy apreciados. ¡gracias chicos!

 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, 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, 0, input.length, 0, 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, 0, 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, 0, 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(); } } } 

Puedes usar el MediaMuxer de Android para empaquetar los flujos crudos creados por MediaCodec en un archivo .mp4. Bonus: los paquetes AAC contenidos en un .mp4 no requieren el encabezado ADTS.

Tengo un ejemplo práctico de esta técnica en Github .

Compruebe el método "testEncoder" aquí para saber cómo usar MediaCodec como codificador correctamente.

Después de eso En su código,

Su entrada (grabadora de audio) está configurada para un solo canal de audio mientras su salida (encabezado de paquete ADTS) está configurada para dos canales (chanCfg = 2).

También si cambia su samplerate de entrada (actualmente 44.1khz) también tiene que cambiar la bandera freqIdx en el encabezado de paquetes ADTS. Compruebe este enlace para conocer los valores válidos.

Y el indicador de perfil de encabezado ADTS se establece en "AAC LC", también se puede encontrar en MediaCodecInfo.CodecProfileLevel . Usted ha fijado el perfil = 2 que es MediaCodecInfo.CodecProfileLevel.AACObjectLC

  • Cómo reducir la latencia en la decodificación de video / avc de MediaCodec
  • No se puede mux tanto de audio como de vídeo
  • Cómo conectar la superficie de Android MediaCodec a Vulkan
  • ¿Cómo depurar errores de MediaCodec a partir de los mensajes OMG logcat?
  • Cómo grabar la pantalla de actividad de la webview con Android MediaCodec?
  • Cómo evitar java.lang.IllegalStateException generado por MediaCodec.dequeueInputBuffer
  • Imágenes a Video usando MediaCodec y MediaMuxer
  • Conseguir que los codificadores QualComm funcionen a través de la API de MediaCodec
  • Decodificador de vídeo acelerado por hardware para H264
  • Codificador AAC de Android MediaCodec
  • Cómo comprimir mp4 video con MediaCodec Android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.