2013-03-07 14 views
22

Ich benutze die MediaCodec Klasse, die vom Android SDK seit API-Ebene 16 mit dem OMX.SEC.aac.enc Encoder zur Verfügung gestellt wird, um Audio in eine Datei zu kodieren. Ich bekomme den Audioeingang aus der Klasse AudioRecord. Meine Instanz der AudioRecord Klasse wird wie folgt konfiguriert:Android MediaCodec AAC Encoder

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

Ich bin in der Lage, die Rohdaten aus der AudioRecord Instanz zu spielen, so dass das Problem dort nicht wohnen.

Ich schreibe den Ausgang von der AudioRecord Instanz in eine ByteBuffer Instanz und übertrage ihn in einen verfügbaren Eingangspuffer vom Encoder. Der Ausgang des Encoders wird in eine Datei auf der SD-Karte geschrieben.

Dies sind die Konfigurationsparameter für meine MediaCodec Beispiel:

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 sagt mir, dass es keine Ströme in meiner aac-Datei sind. Der Befehl FFMPEG -i @[email protected] gibt mir den folgenden Fehler: Ungültige Daten bei der Verarbeitung von Eingang gefunden. Keiner der von mir getesteten Mediaplayer kann meine Datei abspielen.

Warum kann ich meine Datei nicht abspielen? Ich erhalte keine OpenMAX Fehler in LogCat und die Anwendung stürzt beim Codieren nicht ab. Ich habe einen Video-Encoder geschrieben, der nach dem gleichen Prinzip funktioniert und funktioniert.

Dies ist der Code, um die Daten aus der AudioRecord Instanz auf einen Puffer zu lesen:

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

The:

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

Die Funktion von meinem Encoder kopiert den Inhalt eines Puffers zu einem anderen hinzufügen Der folgende Code wird verwendet, um den Eingangspuffer des Codierers zu belegen:

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

Ich schreibe die Ausgabe von dem Encoder in eine lokale Datei wie folgt aus:

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

post die vollständige Methode, wo Sie es tun. mit start() stop() .. danke. –

+1

Sieh dir auch diesen Thread an - https://code.google.com/p/spyroid-ipcamera/issues/detail?id=43, sie scheinen einen funktionierenden Code für die Aufnahme von AAC zu haben. –

+0

@Sergey Benner, Sie verwenden nicht die MediaCodec-Klasse. Die MediaRecorder-Klasse wird in Spydroid verwendet. Diese Klasse wird meine zweite Wahl sein, wenn die MediaCodec-Klasse nicht funktioniert. –

Antwort

2

Ich denke, man vermisste die MediaMauxer Klasse. Sie benötigen es, wenn Sie beispielsweise etwas von MediaCodec in eine Datei schreiben möchten.

+0

OP fragte nach API 16, MediaMuxer wurde mit API 18 eingeführt – muetzenflo

Verwandte Themen