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();
post die vollständige Methode, wo Sie es tun. mit start() stop() .. danke. –
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. –
@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. –