Codificador AAC de Android MediaCodec

Utilizo la clase MediaCodec proporcionada por el SDK de Android desde el nivel 16 de API con el codificador OMX.SEC.aac.enc para codificar audio en un archivo. Recibo la entrada de audio de la clase AudioRecord . Mi instancia de la clase AudioRecord se configura de la siguiente manera:

 bufferSize = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT); recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 44100, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_DEFAULT, bufferSize); 

Puedo jugar los datos sin procesar de la instancia de AudioRecord , así que el problema no reside allí.

Escribo la salida de la instancia AudioRecord a una instancia ByteBuffer y la paso a un búfer de entrada disponible desde el codificador. La salida del codificador se escribe en un archivo de la tarjeta SD.

Estos son los parámetros de configuración de mi instancia de MediaCodec :

 codec = MediaCodec.createEncoderByType("audio/mp4a-latm"); MediaFormat format = new MediaFormat(); format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm"); format.setInteger(MediaFormat.KEY_BIT_RATE, 64 * 1024); format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2); format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100); format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectHE); codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); 

VLC me dice que no hay corrientes en mi archivo aac. El comando FFMPEG -i @filename@ me da el siguiente error: Datos no válidos encontrados al procesar la entrada . Ninguno de los reproductores multimedia que he probado puede reproducir mi archivo.

¿Por qué no puedo reproducir mi archivo? No recibo errores de OpenMAX en LogCat y la aplicación no falla al codificar. Escribí un codificador de vídeo que funciona en el mismo principio y funciona.

Este es el código para leer los datos de la instancia de AudioRecord a un búfer:

  new Thread() { public void run() { ByteBuffer byteBuffer = ByteBuffer.allocateDirect(bufferSize); int read = 0; while (isRecording) { read = recorder.read(byteBuffer, bufferSize); if(AudioRecord.ERROR_INVALID_OPERATION != read){ encoder.add(byteBuffer); } } recorder.stop(); } }.start(); 

La función add de mi codificador copia el contenido de un buffer a otro:

 public void add(ByteBuffer input) { if (!isRunning) return; if (tmpInputBuffer == null) tmpInputBuffer = ByteBuffer.allocate(input.capacity()); if (!tmpBufferClear) Log.e("audio encoder", "deadline missed"); //TODO lower bit rate synchronized (tmpInputBuffer) { tmpInputBuffer.clear(); tmpInputBuffer.put(input); tmpInputBuffer.notifyAll(); Log.d("audio encoder", "pushed data into tmpInputBuffer"); } } 

El código siguiente se utiliza para ocupar el búfer de entrada del codificador:

 new Thread() { public void run() { while (isRunning) { if (tmpInputBuffer == null) continue; synchronized (tmpInputBuffer) { if (tmpBufferClear) { try { Log.d("audio encoder", "falling asleep"); tmpInputBuffer.wait(); //wait when no input is available } catch (InterruptedException e) { e.printStackTrace(); } } ByteBuffer[] inputBuffers = codec.getInputBuffers(); int inputBufferIndex; do inputBufferIndex = codec.dequeueInputBuffer(-1); while (inputBufferIndex < 0); ByteBuffer inputBuffer = inputBuffers[inputBufferIndex]; inputBuffer.clear(); Log.d("input buffer size", String.valueOf(inputBuffer.capacity())); Log.d("tmp input buffer size", String.valueOf(tmpInputBuffer.capacity())); inputBuffer.put(tmpInputBuffer.array()); tmpInputBuffer.clear(); codec.queueInputBuffer(inputBufferIndex, 0, tmpInputBuffer.capacity(), 0, 0); tmpBufferClear = true; Log.d("audio encoder", "added to input buffer"); } } } }.start(); 

Escribo la salida del codificador a un archivo local como este:

  new Thread() { public void run() { while (isRunning) { ByteBuffer[] outputBuffers = codec.getOutputBuffers(); MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); int outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, -1); while (outputBufferIndex >= 0) { ByteBuffer outputBuffer = outputBuffers[outputBufferIndex]; byte[] outData = new byte[bufferInfo.size]; outputBuffer.get(outData); try { fileWriter.write(outData, 0, outData.length); } catch (IOException e) { e.printStackTrace(); } codec.releaseOutputBuffer(outputBufferIndex, false); outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, 0); Log.d("audio encoder", "removed from output buffer"); } } codec.stop(); try { fileWriter.close(); } catch (IOException e) { e.printStackTrace(); } } }.start(); tmpBufferClear = true; Log.d("audio encoder", "added to input buffer"); } } } }.start(); 

Supongo que te perdiste la clase MediaMauxer . Lo necesitas si quieres escribir algo de MediaCodec a un archivo, por ejemplo.

  • Android MediaCodec y la cámara: ¿cómo lograr una mayor velocidad de fotogramas para obtener datos de marco de la cámara?
  • El video codificado y enviado desde Android no se puede reproducir en iOS Telegram
  • ¿Podemos volver a escribir la API de MediaCodec en C?
  • Error de MediaMuxer "Error al detener el muxer"
  • ¿Cómo acceder a EGL Image directamente desde Android Surface para su uso en el decodificador de video MediaCodec?
  • Descodificación del búfer de salida de MediaCodec
  • MediaCodec y PCM de 24 bits
  • No puedo capturar la pantalla de Android con la herramienta de registro de pantalla adb
  • Cómo salvar SurfaceTexture como bitmap
  • Cómo vivir la transmisión desde Android
  • Tiempo de muestra / tiempo de presentación incoherente durante la descodificación de vídeo
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.