Android MediaCodec AAC-Encoder

Ich die MediaCodec Klasse von der Android-SDK-seit API-level 16 mit den OMX.SEC.aac.enc encoder zum Kodieren der Audiodaten in eine Datei. Bekomme ich die audio
Eingang von der AudioRecord Klasse. Mein Beispiel von der AudioRecord Klasse ist so konfiguriert:

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 zu spielen, die raw-Daten aus der AudioRecord Instanz, also das problem nicht dort zu wohnen.

Schreibe ich die Ausgabe von der AudioRecord Instanz zu einer ByteBuffer - Instanz, und übergeben Sie es an einen verfügbaren input-buffer aus dem encoder. Die Ausgabe des encoders in eine Datei geschrieben werden, die auf der SD-Karte.

Diese 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 streams in meine aac-Datei. Der Befehl FFMPEG -i @filename@ gibt mir die folgende Fehlermeldung: Ungültige Daten gefunden, bei der Verarbeitung von input -. Keiner des Mediaplayers muss ich getestet, sind in der Lage zu spielen, meine Datei.

Warum bin ich nicht in der Lage zu spielen, meine Datei? Ich erhalte keine OpenMAX Fehler in LogCat und die Anwendung stürzt nicht mehr ab, wenn die Codierung. Ich schrieb ein video-encoder, der funktioniert nach dem gleichen Prinzip und es funktioniert.

Dies ist der code zum Lesen der Daten aus der AudioRecord Beispiel zu einem buffer:

    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 add aus meiner encoder kopiert den Inhalt von einem Puffer zu einem anderen:

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

Dem folgenden code wird verwendet, um zu besetzen, die den Eingabepuffer des Codierers:

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

Schreibe ich die Ausgabe des encoders in eine lokale Datei wie dieser:

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

InformationsquelleAutor der Frage Bas Palmer | 2013-03-07

Schreibe einen Kommentar