Conversión de PCM a AAC mediante mediacodec

Estoy usando una clase de codec de medios en Android (Jelly Bean) para codificar el formato PCM a AAC. El archivo estaba codificado pero ningún reproductor de música es capaz de reproducir ese archivo. No pude encontrar ningún código de trabajo o documentación apropiada en la red.

Este es mi código:

public void doConvert() { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { try { int codecCount = MediaCodecList.getCodecCount(); for ( int i=0; i < codecCount; i++) { MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i); Logger.getLogger(MainActivity.class.getSimpleName()).log(Level.INFO, info.getName()); for ( String type : info.getSupportedTypes() ) { Logger.getLogger(MainActivity.class.getSimpleName()).log(Level.INFO, type); } } File inputFile = new File( Environment.getExternalStorageDirectory().getAbsolutePath()+"/Download/Ghajini27_Mono_8Khz.wav"); //File inputFile = new File( sampleFD.get); Log.e("File", String.valueOf(inputFile.length())); FileInputStream fis = new FileInputStream(inputFile); fis.skip(44);//remove wav header File outputFile = new File( Environment.getExternalStorageDirectory().getAbsolutePath()+"/Download/out.m4a"); if ( outputFile.exists()) outputFile.delete(); FileOutputStream fos = new FileOutputStream(outputFile); //BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(outputFile)); MediaCodec codec = MediaCodec.createEncoderByType("audio/mp4a-latm"); MediaFormat outputFormat = MediaFormat.createAudioFormat("audio/mp4a-latm", 22050, 1); outputFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC); // outputFormat.setInteger(MediaFormat.KEY_CHANNEL_MASK, AudioFormat.CHANNEL_CONFIGURATION_MONO); outputFormat.setInteger(MediaFormat.KEY_BIT_RATE, 22050 ); outputFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); //outputFormat.setLong(MediaFormat.KEY_MAX_INPUT_SIZE, inputFile.length()); double durationInMs = (inputFile.length()/16000)*1000; Log.e("duration",String.valueOf((long)durationInMs)); outputFormat.setLong(MediaFormat.KEY_DURATION, (long)durationInMs ); codec.configure(outputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE ); codec.start(); ByteBuffer[] inputBuffers = codec.getInputBuffers(); ByteBuffer[] outputBuffer = codec.getOutputBuffers(); boolean hasMoreData = true; MediaCodec.BufferInfo outBuffInfo = new BufferInfo(); byte readBuffer[] = new byte[48000]; byte writeBuffer[] = new byte[48000]; do { int nextBuffer = codec.dequeueInputBuffer(5000); Log.e("NextBuffer","nextInputBuffer = "+nextBuffer); if ( nextBuffer >= 0 ) { ByteBuffer inBuf = inputBuffers[nextBuffer]; inBuf.clear(); int bytesRead = fis.read( readBuffer,0, inBuf.capacity() ); Log.e("bytesread","Read = "+bytesRead); if ( bytesRead < inBuf.capacity() ) { hasMoreData = false; } inBuf.put(readBuffer, 0, bytesRead); codec.queueInputBuffer(nextBuffer, 0, bytesRead, 0, hasMoreData?0:MediaCodec.BUFFER_FLAG_END_OF_STREAM); } int outputBufferIndex = codec.dequeueOutputBuffer( outBuffInfo, 3000); /* logger.log(Level.INFO,"nextOutputBuffer = "+outputBufferIndex); logger.log(Level.INFO,"outBuffInfo offset = "+outBuffInfo.offset); logger.log(Level.INFO,"outBuffInfo size = "+outBuffInfo.size); logger.log(Level.INFO,"outBuffInfo flags = "+outBuffInfo.flags);*/ //while ( outputBufferIndex > -1 ) //{ outputBuffer[outputBufferIndex].position(outBuffInfo.offset); outputBuffer[outputBufferIndex].get(writeBuffer,0,outBuffInfo.size); fos.write(writeBuffer,0, outBuffInfo.size); // logger.log(Level.INFO,"Writing = "+outBuffInfo.size+" bytes"); outputBuffer[outputBufferIndex].clear(); codec.releaseOutputBuffer(outputBufferIndex, false); if ( outBuffInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM ) { codec.flush(); codec.stop(); codec.release(); break; } //outputBufferIndex = codec.dequeueOutputBuffer( outBuffInfo, 1000 ); //logger.log(Level.INFO,"nextOutputBuffer = "+outputBufferIndex); //} } while (outBuffInfo.flags != MediaCodec.BUFFER_FLAG_END_OF_STREAM); fis.close(); fos.flush(); fos.close(); } catch ( Exception e) { //Logger.getLogger(MainActivity.class.getSimpleName()).log(Level.INFO, "Codec Error",e); } //logger.log(Level.INFO,"Done"); return null; } }.execute(); } 

Tendrás que elegir un contenedor para ello. Yo prefiero adts.

Copiar los datos de la carga útil en un aray que es lo suficientemente grande para su contenedor, sólo tiene que añadir en sus bits. Así que después de recurrir a Internet para mi solución he trabajado un fragmento en el lugar

Método 'fillInADTSHeader'

  profile =( configParams[0]>>3 )&0x1f; frequency_index = (this.configParams[0]&0x7) <<1 | (this.configParams[1]>>7) &0x1; channel_config = (this.configParams[1]>>3) &0xf; int finallength = encoded_length + 7; ENCodedByteArray[0] = (byte) 0xff; ENCodedByteArray[1] = (byte) 0xf1; ENCodedByteArray[2] = (byte) ( ((profile - 1) << 6) + (frequency_index << 2) +(channel_config >> 2)); ENCodedByteArray[3] = (byte) (((channel_config & 0x3) << 6) + (finallength >> 11)); ENCodedByteArray[4] = (byte)( (finallength & 0x7ff) >> 3); ENCodedByteArray[5] = (byte) (((finallength & 7) << 5) + 0x1f) ; ENCodedByteArray[6] = (byte) 0xfc; 

Usando algo como

  byte chunkADTS[]=new byte[info.size + 7]; fillInADTSHeader(chunkADTS,info.size); outputBuffers[bR].get(chunkADTS,7,info.size); buffer.pushData(chunkADTS); 

Debe jugar en shoutcast, etc …

Hay una biblioteca de AAC de Android https://github.com/timsu/android-aac-enc

Trate de pasar sus búferes a través de esta biblioteca. Podría ayudar.

  • Android AudioTrack que juega el archivo .wav, consiguiendo solamente el ruido blanco
  • Codificar wav a AAC en Android
  • ¿Cómo se puede conectar un efecto de reverberación a los datos de AudioRecord / PCM y guardarlo en un archivo?
  • Descodificación de archivos de audio y re-codificación al formato PCM deseado: 44,100 kHz, 2 canales, 16 bits
  • Creación de un archivo WAV a partir de datos PCM sin procesar utilizando el SDK de Android
  • Emitir codificación y decodificación de una grabación de audio al formato G711 (PCMU - uLaw)
  • AudioTrack - matriz corta a la distorsión de la matriz del byte usando jlayer (decodificador del java mp3)
  • Dificultad para portar el código de salida de PCM sin procesar de Java a Android AudioTrack API
  • PCM de Android a Ulaw que codifica el archivo wav
  • Mensaje de notificación de AudioTrack corriente
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.