2015-10-12 4 views
6

Мне нужно преобразовать файл PCM в файл AAC или MP4. До сих пор я делал это с MediaCodec и MediaMuxer, но MediaMuxer поддерживается с Android 4.3. Есть ли способ сделать преобразование без использования MediaMuxer?Преобразование PCM в файл AAC или MP4 без MediaMuxer

Мой код заключается в следующем:

MediaMuxer mux = null; 
try { 
    File inputFile = new File(filePath + ".pcm"); 
    FileInputStream fis = new FileInputStream(inputFile); 
    mux = new MediaMuxer(filePath + ".mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); 

    MediaFormat outputFormat = MediaFormat.createAudioFormat(COMPRESSED_AUDIO_FILE_MIME_TYPE, 
      SAMPLING_RATE, 1); 
    outputFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC); 
    outputFormat.setInteger(MediaFormat.KEY_BIT_RATE, COMPRESSED_AUDIO_FILE_BIT_RATE); 

    MediaCodec codec = MediaCodec.createEncoderByType(COMPRESSED_AUDIO_FILE_MIME_TYPE); 
    codec.configure(outputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); 
    codec.start(); 

    ByteBuffer[] codecInputBuffers = codec.getInputBuffers(); 
    ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers(); 

    MediaCodec.BufferInfo outBuffInfo = new MediaCodec.BufferInfo(); 

    byte[] tempBuffer = new byte[BUFFER_SIZE]; 
    boolean hasMoreData = true; 
    double presentationTimeUs = 0; 
    int audioTrackIdx = 0; 
    int totalBytesRead = 0; 
    int percentComplete; 

    do { 

     int inputBufIndex = 0; 
     while (inputBufIndex != -1 && hasMoreData) { 
      inputBufIndex = codec.dequeueInputBuffer(CODEC_TIMEOUT_IN_MS); 

      if (inputBufIndex >= 0) { 
       ByteBuffer dstBuf = codecInputBuffers[inputBufIndex]; 
       dstBuf.clear(); 

       int bytesRead = fis.read(tempBuffer, 0, dstBuf.limit()); 
       if (bytesRead == -1) { // -1 implies EOS 
        hasMoreData = false; 
        codec.queueInputBuffer(inputBufIndex, 0, 0, (long) presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM); 
       } else { 
        totalBytesRead += bytesRead; 
        dstBuf.put(tempBuffer, 0, bytesRead); 
        codec.queueInputBuffer(inputBufIndex, 0, bytesRead, (long) presentationTimeUs, 0); 
        presentationTimeUs = 1000000l * (totalBytesRead/2)/SAMPLING_RATE; 
       } 
      } 
     } 

     // Drain audio 
     int outputBufIndex = 0; 
     while (outputBufIndex != MediaCodec.INFO_TRY_AGAIN_LATER) { 

      outputBufIndex = codec.dequeueOutputBuffer(outBuffInfo, CODEC_TIMEOUT_IN_MS); 
      if (outputBufIndex >= 0) { 
       ByteBuffer encodedData = codecOutputBuffers[outputBufIndex]; 
       encodedData.position(outBuffInfo.offset); 
       encodedData.limit(outBuffInfo.offset + outBuffInfo.size); 

       if ((outBuffInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0 && outBuffInfo.size != 0) { 
        codec.releaseOutputBuffer(outputBufIndex, false); 
       } else { 

        mux.writeSampleData(audioTrackIdx, codecOutputBuffers[outputBufIndex], outBuffInfo); 
        codec.releaseOutputBuffer(outputBufIndex, false); 
       } 
      } else if (outputBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 
       outputFormat = codec.getOutputFormat(); 
       Log.v("AUDIO", "Output format changed - " + outputFormat); 
       audioTrackIdx = mux.addTrack(outputFormat); 
       mux.start(); 
      } else if (outputBufIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { 
       Log.e("AUDIO", "Output buffers changed during encode!"); 
      } else if (outputBufIndex != MediaCodec.INFO_TRY_AGAIN_LATER){ 
       Log.e("AUDIO", "Unknown return code from dequeueOutputBuffer - " + outputBufIndex); 
      } 
     } 
     percentComplete = (int) Math.round(((float) totalBytesRead/(float) inputFile.length()) * 100.0); 
     Log.v("AUDIO", "Conversion % - " + percentComplete); 
    } while (outBuffInfo.flags != MediaCodec.BUFFER_FLAG_END_OF_STREAM); 

    fis.close(); 
    mux.stop(); 
    mux.release(); 
+1

Closevoter: обратите внимание, что ответы на рекомендуемые инструменты не означают, что вопрос требует инструментов и делает его не по теме. –

ответ

4

Как уже отмечалось, есть нет государственной системы API совместимы с более старой версией Android для такого рода работы.

Во всяком случае, вы можете продолжить собственное решение , используя нативный кодер (как FFMPEG). Я предложил вам следующее: timsu/android-aac-enc

Android AAC кодировщик проект

Экстракция Android Stagefright VO AAC энкодер с хорошей Java API.

Этот проект предлагает простой Java API для базового кодера JNI, и он должен быть готов к использованию, так как родной библиотеки уже скомпилированные для общего ARM архитектуры (обратите внимание, что я гавань» t проверил его). Вся библиотека всего лишь 500kb, поэтому она не будет откармливать ваш APK.

Для быстрого теста, импорт в проекте следующие части:

  1. Java bindings нативного AAC encorder
  2. Предварительно скомпилированные AAC encoder .so library
  3. Example использования (речевое кодирование)

Вы должны иметь возможность легко адаптировать пример к вашему коду.