2015-10-12 23 views
6

Ich muss eine PCM-Datei in AAC oder MP4-Datei konvertieren. Bis jetzt habe ich es mit MediaCodec und MediaMuxer gemacht, aber MediaMuxer wird von Android 4.3 unterstützt. Gibt es eine Methode, die Konvertierung ohne die Verwendung von MediaMuxer durchzuführen?Konvertieren PCM in AAC oder MP4-Datei ohne MediaMuxer

Mein Code ist dies:

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: Bitte beachten Sie, dass Antworten, die Tools empfehlen, nicht bedeuten, dass eine Frage nach Tools fragt und sie nicht zum Thema macht. –

Antwort

4

Wie Sie bereits darauf hingewiesen, gibt es kein öffentliches System API kompatibel mit älterer Version von Android für diese Art von Arbeit.

Wie auch immer, können Sie eine benutzerdefinierte Lösung verfolgen mit einem nativen Encoder (wie FFMPEG). Ich kann vorgeschlagen, dass Sie die folgenden Schritte aus: timsu/android-aac-enc

Android AAC Encoder Projekt

Extraktion von Android Stagefright VO AAC-Codierer mit einem schönen Java API.

Dieses Projekt bietet einen einfachen Java-API für den zugrunde liegenden JNI-Encoder, und es sollte, da die native Bibliothek einsatzbereit sein wird bereits für generische ARM kompiliert Architekturen (bitte beachten Sie, dass ich haven‘ t teste es). Die ganze Bibliothek ist nur 500kb so wird es nicht Ihre APK so viel mästen.

Für einen schnellen Test, Import in Ihrem Projekt die folgenden Teile:

  1. Java bindings für die native AAC Encorder
  2. vorkompilierte AAC encoder .so library
  3. Example Nutzungs (Sprachcodierung)

Sie sollten das Beispiel einfach an Ihren Code anpassen können.