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 x11
so 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 x8
und 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
-
Können Sie richtig optimieren mein Beispiel-code, um korrekt zu arbeiten?
-
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 |
Du musst angemeldet sein, um einen Kommentar abzugeben.
Nach der Prüfung das ist, was ich kam mit ändern Sie Ihren code:
InformationsquelleAutor der Antwort
Selbst Beantworten, hier mein bester Versuch bisher
InformationsquelleAutor der Antwort
Ich habe versucht den obigen code und es hat nicht richtig funktioniert.Ich war immer viel Stille injiziert, um die decodierte Ausgabe. Problem war die Einstellung nicht die richtige "csd" Wert in den decoder.
Also, wenn Sie sehen, "Stille", die in den log oder Decoder werfen Fehler stellen Sie sicher, dass Sie Hinzugefügt haben, die folgenden an Ihre Medien-decoder-format
InformationsquelleAutor der Antwort
Ihre Netzwerk-code ist die Verknüpfung von Daten. Sie bekam 369 bytes der komprimierten Daten, sondern auf der Empfängerseite Sie endete mit 1024 bytes. Diese 1024 bytes bestehen aus zwei ganzen und einer teilweisen frame. Die zwei ganze frames, jeder Dekodieren von 4096 bytes wieder, für den insgesamt 8192 bytes, die Sie gesehen haben. Die restlichen partiellen Rahmen wird wahrscheinlich dekodiert werden, wenn Sie senden ausreichend mehr Daten an den decoder, aber Sie sollten in der Regel versenden nur ganze frames an den decoder.
Darüber hinaus
MediaCodec.dequeueOutputBuffer()
nicht nur (positiv) Puffer-Indizes, aber auch (negativ) status-codes. Eine der möglichen codes istMediaCodec.INFO_OUTPUT_FORMAT_CHANGED
was bedeutet, dass Sie benötigen, rufen SieMediaCodec.getOutputFormat()
um das format der audio-Daten. Sie könnten finden Sie in der codec-Ausgang stereo, auch wenn die Eingabe war mono. Der code, den Sie geschrieben einfach bricht aus der Schleife, wenn es bekommt man diese status-codes.InformationsquelleAutor der Antwort
Ich getestet habe, mit Ihrer Quelle.
es gibt einige Punkte.
Bit-Rate ist eine Natürliche Zahl mit K, aber nicht computer-K.
64 Kb = 64000, aber nicht 64 * 1024
Es ist nicht empfohlen, zu schreiben, einen langen code, der die Aktien einiger Variablen.
A. separate Encoder-Thread und der Decoder-Thread in 2 unabhängigen Klassen.
B. Die DatagramSocket wird gemeinsam von Sender und Empfänger, ist es nicht gut.
Auflisten Audio-Format benötigen Sie mehr Werte.
also sample-raten sollten ausgewählt werden aus : 8000, 11025, 22050, 44100
InformationsquelleAutor der Antwort
D/AudioRecoder﹕ 4096 bytes zu Lesen
D/AudioEncoder﹕ 360 bytes kodiert
D/UDP-Empfänger﹕ habe !!! aus /127.0.0.1:39000
D/UDP-Empfänger﹕ 360 bytes
D/AudioDecoder﹕ 8192 bytes decodiert
D/AudioRecoder﹕ 8192 bytes Lesen
D/AudioEncoder﹕ 360 bytes kodiert
D/UDP-Empfänger﹕ habe !!! aus /127.0.0.1:39000
D/UDP-Empfänger﹕ 360 bytes
D/AudioDecoder﹕ 8192 bytes decodiert
InformationsquelleAutor der Antwort