2016-06-03 3 views
0

У меня есть аудиофайл AAC-формата, который я пытаюсь преобразовать в файл PCM с необработанным форматом, чтобы смешать его с другим аудиофайлом и воспроизвести его с помощью AudioTrack позже.Декодирование аудиофайла AAC в файл RAW PCM

После некоторого исследования я наткнулся на this library, который соответствующим образом декодирует мой файл AAC. Тем не менее, он передает только декодированные байты непосредственно в AudioTrack. При попытке записать декодированные байты в выходной поток вместо этого, результирующий файл содержит только шум.

это код, я использую для декодирования AAC файла -

public void AACDecoderAndPlay() { 
    ByteBuffer[] inputBuffers = mDecoder.getInputBuffers(); 
    ByteBuffer[] outputBuffers = mDecoder.getOutputBuffers(); 

    BufferInfo info = new BufferInfo(); 

    // create an audiotrack object 
    AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, JamboxAudioTrack.FREQUENCY, 
      JamboxAudioTrack.CHANNEL_CONFIGURATION, JamboxAudioTrack.AUDIO_ENCODING, 
      JamboxAudioTrack.BUFFER_SIZE, AudioTrack.MODE_STREAM); 

    audioTrack.play(); 


    long bytesWritten = 0; 
    while (!eosReceived) { 
     int inIndex = mDecoder.dequeueInputBuffer(TIMEOUT_US); 
     if (inIndex >= 0) { 
      ByteBuffer buffer = inputBuffers[inIndex]; 
      int sampleSize = mExtractor.readSampleData(buffer, 0); 
      if (sampleSize < 0) { 
       // We shouldn't stop the playback at this point, just pass the EOS 
       // flag to mDecoder, we will get it again from the 
       // dequeueOutputBuffer 
       Log.d(LOG_TAG, "InputBuffer BUFFER_FLAG_END_OF_STREAM"); 
       mDecoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); 

      } else { 
       mDecoder.queueInputBuffer(inIndex, 0, sampleSize, mExtractor.getSampleTime(), 0); 
       mExtractor.advance(); 
      } 

      int outIndex = mDecoder.dequeueOutputBuffer(info, TIMEOUT_US); 
      switch (outIndex) { 
       case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED: 
        Log.d(LOG_TAG, "INFO_OUTPUT_BUFFERS_CHANGED"); 
        outputBuffers = mDecoder.getOutputBuffers(); 
        break; 

       case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED: 
        MediaFormat format = mDecoder.getOutputFormat(); 
         Log.d(LOG_TAG, "New format " + format); 
//      audioTrack.setPlaybackRate(format.getInteger(MediaFormat.KEY_SAMPLE_RATE)); 

         break; 

       case MediaCodec.INFO_TRY_AGAIN_LATER: 
        Log.d(LOG_TAG, "dequeueOutputBuffer timed out!"); 
        break; 

       default: 
        ByteBuffer outBuffer = outputBuffers[outIndex]; 
        Log.v(LOG_TAG, "We can't use this buffer but render it due to the API limit, " + outBuffer); 

        final byte[] chunk = new byte[info.size]; 
        outBuffer.get(chunk); // Read the buffer all at once 
        outBuffer.clear(); // ** MUST DO!!! OTHERWISE THE NEXT TIME YOU GET THIS SAME BUFFER BAD THINGS WILL HAPPEN 

        audioTrack.write(chunk, info.offset, info.offset + info.size); // AudioTrack write data 

        if (info.offset > 0) { 
         Log.v(LOG_TAG, "" + info.offset); 
        } 
        try { 
         mOutputStream.write(chunk, info.offset, info.offset + info.size); 
         bytesWritten += info.offset + info.size; 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } 
        mDecoder.releaseOutputBuffer(outIndex, false); 
        break; 
      } 

      // All decoded frames have been rendered, we can stop playing now 
      if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { 
       Log.d(LOG_TAG, "OutputBuffer BUFFER_FLAG_END_OF_STREAM"); 
       break; 
      } 
     } 
    } 
    Log.v(LOG_TAG, "Bytes written: " + bytesWritten); 

    mDecoder.stop(); 
    mDecoder.release(); 
    mDecoder = null; 

    mExtractor.release(); 
     mExtractor = null; 

     audioTrack.stop(); 
     audioTrack.release(); 
     audioTrack = null; 
    } 

Для воспроизведения декодированного файла я использую простую аудиодорожку, который читает и играет из буфера -

public void start() { 
    new Thread(new Runnable() { 
     public void run() { 
      try { 
       Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO); 
       InputStream inputStream = new FileInputStream(playingFile); 
       BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); 
       DataInputStream dataInputStream = new DataInputStream(bufferedInputStream); 

       AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, FREQUENCY, 
         CHANNEL_CONFIGURATION, AUDIO_ENCODING, BUFFER_SIZE, AudioTrack.MODE_STREAM); 

       short[] buffer = new short[BUFFER_SIZE/4]; 
       long startTime = System.currentTimeMillis(); 

       track.play(); 

       while (dataInputStream.available() > 0) { 
        int i = 0; 
        while (dataInputStream.available() > 0 && i < buffer.length 

) { 
          buffer[i] = dataInputStream.readShort(); 
          i++; 
         } 
         track.write(buffer, 0, buffer.length); 
         if (latency < 0) { 
          latency = System.currentTimeMillis() - startTime; 
         } 
        } 
// 
//   int i = 0; 
//   while((i = dataInputStream.read(buffer, 0, BUFFER_SIZE)) > -1){ 
//    track.write(buffer, 0, i); 
//   } 
        track.stop(); 
        track.release(); 
        dataInputStream.close(); 
        inputStream.close(); 
       } 
       catch (Exception e) 
       { 
        e.printStackTrace(); 
       } 
      } 
    }).start(); 
} 

Что я Я пропустил?

ответ

0

Ваша проблема заключается в том, что вы пишете свой вывод как простые байты (я не вижу настройки mOutputStream в вашем коде). Эти простые байты будут находиться в исходной консистенции вашей платформы (на практике, немного endian), но читают ее как shorts, используя DataInputStream независимым от платформы способом (который указан как большой endian).

Самый простой способ решить эту проблему - использовать массив byte вместо массива short при воспроизведении его; AudioTrack принимает как байтовые, так и короткие массивы, а когда задан массив байтов, он интерпретирует его правильным (родным) способом, который соответствует выходу MediaCodec. Просто убедитесь, что размер буфера равно четному количеству байтов.

Если вам действительно нужно иметь значения как short s, вам нужно использовать считыватель, который читает в маленьком суточном режиме (все текущие Android-приложения ABI мало ориентированы). Для этого, похоже, нет простого API-интерфейса, но на практике это не так сложно. См. метод readLittleShort в Java : DataInputStream replacement for endianness для примера о том, как это сделать.

+0

Endianness, похоже, всегда будет проблемой :) Непонимание этого процесса заставило меня написать реализацию AudioTrack совершенно неправильно. Спасибо большое! –

Смежные вопросы