Преобразование PCM в AAC с использованием mediacodec

Я использую класс медиакодека в Android (Jelly Bean) для кодирования формата PCM в AAC. Файл был закодирован, но музыкальный проигрыватель не смог воспроизвести этот файл. Я не смог найти какой-либо рабочий код или соответствующую документацию в сети.

Это мой код:

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(); } 

Вам нужно будет выбрать контейнер для него. Я предпочитаю адтов.

Скопируйте данные полезной нагрузки в aray, который достаточно велик для вашего контейнера, просто добавьте свои биты. Итак, после очистки Интернета для моего решения я применил некоторые фрагменты

Метод '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; 

Используя что-то вроде

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

Должен играть в крик и т. Д. …

Там есть андроидная библиотека AAC https://github.com/timsu/android-aac-enc

Попробуйте передать свои буферы через эту библиотеку. Это может помочь.