PCM - & gt; AAC (Encoder) - & gt; PCM (Decoder) in Echtzeit mit korrekter Optimierung

Ich versuche, umzusetzen

AudioRecord (MIC) ->

PCM -> AAC Encoder
AAC -> PCM Decode

-> AudioTrack??  (SPEAKER)

mit MediaCodec auf Android 4.1+ (API16).

Erstens, habe ich erfolgreich (aber sicher nicht richtig optimiert) umgesetzt PCM -> AAC Encoder durch MediaCodec wie vorgesehen, wie unten

private boolean setEncoder(int rate)
{
    encoder = MediaCodec.createEncoderByType("audio/mp4a-latm");
    MediaFormat format = new MediaFormat();
    format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
    format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
    format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100);
    format.setInteger(MediaFormat.KEY_BIT_RATE, 64 * 1024);//AAC-HE 64kbps
    format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectHE);
    encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
    return true;
}

EINGANG: PCM Bitrate = 44100(Hz) x 16(bit) x 1(Monoral) = 705600 bit/s

AUSGANG: AAC-ER Bitrate = 64 x 1024(bit) = 65536 bit/s

So, die Größe der Daten etwa komprimiert x11 ,und ich bestätigte diese Arbeit durch die Beobachtung einer log -

  • AudioRecoder﹕ 4096 bytes, die gelesen
  • AudioEncoder﹕ 369 bytes codiert

Größe der Daten etwa komprimiert x11so weit so gut.

Nun, ich habe einen UDP-server zum empfangen der kodierten Daten dann entschlüsseln.

Den decoder-Profil ist wie folgt festgelegt:

private boolean setDecoder(int rate)
{
    decoder = MediaCodec.createDecoderByType("audio/mp4a-latm");
    MediaFormat format = new MediaFormat();
    format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
    format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
    format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100);
    format.setInteger(MediaFormat.KEY_BIT_RATE, 64 * 1024);//AAC-HE 64kbps
    format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectHE);
    decoder.configure(format, null, null, 0);

    return true;
}

Seit UDPserver packet buffer size ist 1024

  • UDPserver ﹕ 1024 bytes empfangen

und da dies ist der komprimierte AAC-Daten, würde ich erwarten, dass die Dekodierung wird die Größe

etwa 1024 x11 aber das tatsächliche Ergebnis ist

  • AudioDecoder﹕ 8192 bytes decodiert

Es ist etwa x8und ich fühle mich etwas falsch.

Den decoder-code ist wie folgt:

    IOudpPlayer = new Thread(new Runnable()
    {
        public void run()
        {
            SocketAddress sockAddress;
            String address;

            int len = 1024;
            byte[] buffer2 = new byte[len];
            DatagramPacket packet;

            byte[] data;

            ByteBuffer[] inputBuffers;
            ByteBuffer[] outputBuffers;

            ByteBuffer inputBuffer;
            ByteBuffer outputBuffer;

            MediaCodec.BufferInfo bufferInfo;
            int inputBufferIndex;
            int outputBufferIndex;
            byte[] outData;
            try
            {
                decoder.start();
                isPlaying = true;
                while (isPlaying)
                {
                    try
                    {
                        packet = new DatagramPacket(buffer2, len);
                        ds.receive(packet);

                        sockAddress = packet.getSocketAddress();
                        address = sockAddress.toString();

                        Log.d("UDP Receiver"," received !!! from " + address);

                        data = new byte[packet.getLength()];
                        System.arraycopy(packet.getData(), packet.getOffset(), data, 0, packet.getLength());

                        Log.d("UDP Receiver",  data.length + " bytes received");

                        //===========
                        inputBuffers = decoder.getInputBuffers();
                        outputBuffers = decoder.getOutputBuffers();
                        inputBufferIndex = decoder.dequeueInputBuffer(-1);
                        if (inputBufferIndex >= 0)
                        {
                            inputBuffer = inputBuffers[inputBufferIndex];
                            inputBuffer.clear();

                            inputBuffer.put(data);

                            decoder.queueInputBuffer(inputBufferIndex, 0, data.length, 0, 0);
                        }

                        bufferInfo = new MediaCodec.BufferInfo();
                        outputBufferIndex = decoder.dequeueOutputBuffer(bufferInfo, 0);

                        while (outputBufferIndex >= 0)
                        {
                            outputBuffer = outputBuffers[outputBufferIndex];

                            outputBuffer.position(bufferInfo.offset);
                            outputBuffer.limit(bufferInfo.offset + bufferInfo.size);

                            outData = new byte[bufferInfo.size];
                            outputBuffer.get(outData);

                            Log.d("AudioDecoder", outData.length + " bytes decoded");

                            decoder.releaseOutputBuffer(outputBufferIndex, false);
                            outputBufferIndex = decoder.dequeueOutputBuffer(bufferInfo, 0);

                        }



                        //===========

                    }
                    catch (IOException e)
                    {
                    }
                }

                decoder.stop();

            }
            catch (Exception e)
            {
            }
        }
    });

der vollständige code:

https://gist.github.com/kenokabe/9029256

müssen auch die Erlaubnis:

 <uses-permission android:name="android.permission.INTERNET"></uses-permission>
 <uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission>

Mitglied fadden wer für Google arbeitet, erzählte mir

Sieht aus wie ich bin nicht die Einstellung der position & limit auf der output-Puffer.

Habe ich gelesen
VP8-Encoding Nexus 5 gibt leer/0-Frames , aber nicht sicher, wie Sie korrekt implementieren.


UPDATE: ich habe irgendwie verstanden, wo zu ändern für

Sieht aus wie ich bin nicht die Einstellung der position & limit auf der output-Puffer.

so fügen 2 Zeilen innerhalb der while-Schleife der Encoder und der Decoder wie folgt:

 outputBuffer.position(bufferInfo.offset);
 outputBuffer.limit(bufferInfo.offset + bufferInfo.size);

https://gist.github.com/kenokabe/9029256/revisions

Aber das Ergebnis ist das gleiche.

und jetzt, denke ich, der Fehler:
W/SoftAAC2﹕ AAC decoder returned error 16388, substituting silence. zeigt an, dass dieser decoder nicht völlig von der ersten. Es ist wieder the data is not seekable Problem. Suche im AAC-streams auf Android Es ist sehr enttäuschend, wenn der AAC-decoder kann nicht mit der streaming-Daten auf diese Weise aber nur mit dem hinzufügen von ein paar header.


UPDATE2: UDP-receiver falsch war, so geändert

https://gist.github.com/kenokabe/9029256

Nun, der Fehler

W/SoftAAC2﹕ AAC decoder returned error 16388, substituting silence.
verschwunden!!

So, es gibt die decoder arbeitet ohne Fehler, zumindest,

jedoch, dies ist der log von 1 Zyklus:

D/AudioRecoder 4096 bytes read
D/AudioEncoder 360 bytes encoded
D/UDP Receiver received !!! from /127.0.0.1:39000
D/UDP Receiver 360 bytes received
D/AudioDecoder 8192 bytes decoded

PCM(4096)->AACencoded(360)->UDP-AAC(360)->(sollen )PCM(8192)

Das endgültige Ergebnis ist ungefähr 2x die Größe des original-PCM, etwas ist immer noch falsch.


Also meine Frage wäre hier

  1. Können Sie richtig optimieren mein Beispiel-code, um korrekt zu arbeiten?

  2. Ist es eine richtige Weg, um die Verwendung AudioTrack API zu spielen die dekodierten PCM-raw-Daten auf der fliege, und können Sie mir zeigen, der richtige Weg, das zu tun? Ein Beispiel-code dankbar.

Danke.

PS. Mein Projekt zielt auf Android4.1+(API16), die ich gelesen habe, sind die Dinge einfacher auf API18(Andeoid 4.3+), aber aus offensichtlichen Gründen der Kompatibilität habe ich leider überspringen MediaMuxer etc. hier...

InformationsquelleAutor der Frage | 

Schreibe einen Kommentar