2013-03-07 512 views
22

我使用Android SDK提供的MediaCodec類,API級別爲16,OMX.SEC.aac.enc編碼器將音頻編碼爲文件。我從AudioRecord類獲得音頻 輸入。我的AudioRecord類的實例配置是這樣的:Android MediaCodec AAC編碼器

bufferSize = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT); 
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 44100, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_DEFAULT, bufferSize); 

我能夠從AudioRecord實例玩的原始數據,所以問題不在於那裏。

我將AudioRecord實例的輸出寫入ByteBuffer實例,並將其從編碼器傳遞到可用輸入緩衝區。編碼器的輸出寫入SD卡上的文件。

這些是我MediaCodec實例的配置參數:

codec = MediaCodec.createEncoderByType("audio/mp4a-latm"); 
MediaFormat format = new MediaFormat(); 
format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm"); 
format.setInteger(MediaFormat.KEY_BIT_RATE, 64 * 1024); 
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2); 
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100); 
format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectHE); 
codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); 

VLC告訴我,有我的AAC文件中沒有流。命令FFMPEG -i @[email protected]給我以下錯誤:處理輸入時發現無效數據。我測試的媒體播放器都不能播放我的文件。

爲什麼我無法播放我的文件? LogCat中沒有收到OpenMAX錯誤,編碼時應用程序不會崩潰。我寫了一個視頻編碼器,其工作原理相同,並且工作正常。

這是從AudioRecord實例中的數據讀取到緩存代碼:

new Thread() { 
     public void run() { 
      ByteBuffer byteBuffer = ByteBuffer.allocateDirect(bufferSize); 
      int read = 0; 
      while (isRecording) { 
       read = recorder.read(byteBuffer, bufferSize); 
       if(AudioRecord.ERROR_INVALID_OPERATION != read){ 
        encoder.add(byteBuffer); 
       } 
      } 
      recorder.stop(); 
     } 
    }.start(); 

功能從我的編碼器複製一個緩衝區的內容添加到另一個:

public void add(ByteBuffer input) { 
    if (!isRunning) 
     return; 

    if (tmpInputBuffer == null) 
     tmpInputBuffer = ByteBuffer.allocate(input.capacity()); 

    if (!tmpBufferClear) 
     Log.e("audio encoder", "deadline missed"); //TODO lower bit rate 

    synchronized (tmpInputBuffer) { 
     tmpInputBuffer.clear(); 
     tmpInputBuffer.put(input); 
     tmpInputBuffer.notifyAll(); 
     Log.d("audio encoder", "pushed data into tmpInputBuffer"); 
    } 
} 

的以下代碼用於佔用編碼器的輸入緩衝區:

new Thread() { 
    public void run() { 
     while (isRunning) { 
      if (tmpInputBuffer == null) 
       continue; 
      synchronized (tmpInputBuffer) { 
       if (tmpBufferClear) { 
        try { 
         Log.d("audio encoder", "falling asleep"); 
         tmpInputBuffer.wait(); //wait when no input is available 
        } 
        catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 

       ByteBuffer[] inputBuffers = codec.getInputBuffers(); 
       int inputBufferIndex; 
       do 
        inputBufferIndex = codec.dequeueInputBuffer(-1); 
       while (inputBufferIndex < 0); 
       ByteBuffer inputBuffer = inputBuffers[inputBufferIndex]; 
       inputBuffer.clear(); 
       Log.d("input buffer size", String.valueOf(inputBuffer.capacity())); 
       Log.d("tmp input buffer size", String.valueOf(tmpInputBuffer.capacity())); 
       inputBuffer.put(tmpInputBuffer.array()); 
       tmpInputBuffer.clear(); 
       codec.queueInputBuffer(inputBufferIndex, 0, tmpInputBuffer.capacity(), 0, 0); 
       tmpBufferClear = true; 
       Log.d("audio encoder", "added to input buffer"); 
      } 
     } 
    } 
}.start(); 

我寫從編碼器到本地文件的輸出是這樣的:

new Thread() { 
     public void run() { 
      while (isRunning) { 
       ByteBuffer[] outputBuffers = codec.getOutputBuffers(); 
       MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); 
       int outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, -1); 
       while (outputBufferIndex >= 0) { 
        ByteBuffer outputBuffer = outputBuffers[outputBufferIndex]; 
        byte[] outData = new byte[bufferInfo.size]; 
        outputBuffer.get(outData); 

        try { 
         fileWriter.write(outData, 0, outData.length); 
        } 
        catch (IOException e) { 
         e.printStackTrace(); 
        } 
        codec.releaseOutputBuffer(outputBufferIndex, false); 
        outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, 0); 
        Log.d("audio encoder", "removed from output buffer"); 
       } 
      } 
      codec.stop(); 

      try { 
       fileWriter.close(); 
      } 
      catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
    }.start(); 
       tmpBufferClear = true; 
       Log.d("audio encoder", "added to input buffer"); 
      } 
     } 
    } 
}.start(); 
+0

發佈完整的方法,你這樣做。用start()stop()..謝謝。 – 2013-03-07 17:08:33

+1

另外,看看這個主題 - https://code.google.com/p/spydroid-ipcamera/issues/detail?id=43他們似乎有一段代碼用於在那裏錄製AAC。 – 2013-03-07 17:24:00

+0

@Sergey Benner,他們不使用MediaCodec類。 MediaRecorder類在Spydroid中使用。如果MediaCodec類不起作用,該類將是我的第二選擇。 – 2013-03-08 08:59:52

回答

2

我猜你錯過了MediaMauxer類。例如,如果你想從MediaCodec獲得一些文件,你需要它。

+0

OP要求提供API 16,MediaMuxer隨API 18引入 – muetzenflo 2016-06-24 11:47:15

相關問題