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:
- Cómo convertir archivos .pcm a .wav o .mp3?
- ¿Cómo obtener la frecuencia del resultado fft?
- ¿Puedo obtener datos crudos de cpm de MediaPlayer o SoundPool?
- PCM -> AAC (Encoder) -> PCM (Decodificador) en tiempo real con optimización correcta
- Escritura de datos grabados PCM en un archivo .wav (java android)
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(); }
- Conversión de archivos MIDI a audio sin procesar utilizando un sintetizador de software
- ¿Cómo puedo obtener datos de frecuencia de PCM usando FFT
- ¿Valores de amplitud de audio PCM?
- JTransforms FFT en Android de datos de PCM
- Android MediaPlayer hace que el juego se congele con "AudioHardware pcm la reproducción se va a esperar"
- Android AudioRecord y AudioTrack codec opciones?
- Convertir PCM-16 a AMR usando AmrInputStream
- Manera correcta de convertir datos de onda PCM de 16 bits a flotar
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: Skip Gradle "testClasses" tarea para un proyecto de dependencia
- Cómo crear un observable de OnClick evento Android?