package lzf.video.edit.decoder;
import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.util.Log;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
class AACAudioEncoder extends AudioEncoder {
private final static String TAG = "AACAudioEncoder";
private final static String AUDIO_MIME = "audio/mp4a-latm";
private final static long audioBytesPerSample = 44100 * 16 / 8;
AACAudioEncoder(String rawAudioFile) {
super(rawAudioFile);
}
@Override
public void encodeToFile(String outEncodeFile) {
FileInputStream fisRawAudio = null;
FileOutputStream fosAccAudio = null;
try {
fisRawAudio = new FileInputStream(rawAudioFile);
fosAccAudio = new FileOutputStream(outEncodeFile);
final MediaCodec audioEncoder = createACCAudioDecoder();
audioEncoder.start();
ByteBuffer[] audioInputBuffers = audioEncoder.getInputBuffers();
ByteBuffer[] audioOutputBuffers = audioEncoder.getOutputBuffers();
boolean sawInputEOS = false;
boolean sawOutputEOS = false;
long audioTimeUs = 0;
BufferInfo outBufferInfo = new BufferInfo();
boolean readRawAudioEOS = false;
byte[] rawInputBytes = new byte[4096];
int readRawAudioCount = 0;
int rawAudioSize = 0;
long lastAudioPresentationTimeUs = 0;
int inputBufIndex, outputBufIndex;
while (!sawOutputEOS) {
if (!sawInputEOS) {
inputBufIndex = audioEncoder.dequeueInputBuffer(10000);
if (inputBufIndex >= 0) {
ByteBuffer inputBuffer = audioInputBuffers[inputBufIndex];
inputBuffer.clear();
int bufferSize = inputBuffer.remaining();
if (bufferSize != rawInputBytes.length) {
rawInputBytes = new byte[bufferSize];
}
if (!readRawAudioEOS) {
readRawAudioCount = fisRawAudio.read(rawInputBytes);
if (readRawAudioCount == -1) {
readRawAudioEOS = true;
}
}
if (readRawAudioEOS) {
audioEncoder.queueInputBuffer(inputBufIndex, 0, 0,0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
sawInputEOS = true;
} else {
inputBuffer.put(rawInputBytes, 0, readRawAudioCount);
rawAudioSize += readRawAudioCount;
audioEncoder.queueInputBuffer(inputBufIndex, 0,readRawAudioCount, audioTimeUs, 0);
audioTimeUs = (long) (1000000 * (rawAudioSize / 2.0) / audioBytesPerSample);
}
}
}
outputBufIndex = audioEncoder.dequeueOutputBuffer(outBufferInfo, 10000);
if (outputBufIndex >= 0) {
// Simply ignore codec config buffers.
if ((outBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
audioEncoder.releaseOutputBuffer(outputBufIndex, false);
continue;
}
if (outBufferInfo.size != 0) {
ByteBuffer outBuffer = audioOutputBuffers[outputBufIndex];
outBuffer.position(outBufferInfo.offset);
outBuffer.limit(outBufferInfo.offset+ outBufferInfo.size);
// if (lastAudioPresentationTimeUs < outBufferInfo.presentationTimeUs) {
lastAudioPresentationTimeUs = outBufferInfo.presentationTimeUs;
int outBufSize = outBufferInfo.size;
int outPacketSize = outBufSize + 7;
outBuffer.position(outBufferInfo.offset);
outBuffer.limit(outBufferInfo.offset + outBufSize);
byte[] outData = new byte[outBufSize + 7];
addADTStoPacket(outData, outPacketSize);
outBuffer.get(outData, 7, outBufSize);
fosAccAudio.write(outData, 0, outData.length);
// } else {
// Log.e(TAG,
// "error sample! its presentationTimeUs should not lower than before.");
// }
}
audioEncoder.releaseOutputBuffer(outputBufIndex, false);
if ((outBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
sawOutputEOS = true;
}
} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
audioOutputBuffers = audioEncoder.getOutputBuffers();
} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat audioFormat = audioEncoder.getOutputFormat();
Log.i(TAG, "format change : " + audioFormat);
}
}
Log.i(TAG,"acc encode done");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fisRawAudio != null)
fisRawAudio.close();
if (fosAccAudio != null)
fosAccAudio.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private MediaCodec createACCAudioDecoder() throws IOException {
MediaCodec codec = MediaCodec.createEncoderByType(AUDIO_MIME);
MediaFormat format = new MediaFormat();
format.setString(MediaFormat.KEY_MIME, AUDIO_MIME);
format.setInteger(MediaFormat.KEY_BIT_RATE, 128000);
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2);
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100);
format.setInteger(MediaFormat.KEY_AAC_PROFILE,
MediaCodecInfo.CodecProfileLevel.AACObjectLC);
codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
return codec;
}
/**
* Add ADTS header at the beginning of each and every AAC packet. This is
* needed as MediaCodec encoder generates a packet of raw AAC data.
*
* Note the packetLen must count in the ADTS header itself.
**/
private void addADTStoPacket(byte[] packet, int packetLen) {
int profile = 2; // AAC LC
int freqIdx = 4; // 44.1KHz
int chanCfg = 2; // Channel Configurations
// fill in ADTS data
packet[0] = (byte) 0xFF;
packet[1] = (byte) 0xF9;
packet[2] = (byte) (((profile - 1) << 6) + (freqIdx << 2) + (chanCfg >> 2));
packet[3] = (byte) (((chanCfg & 3) << 6) + (packetLen >> 11));
packet[4] = (byte) ((packetLen & 0x7FF) >> 3);
packet[5] = (byte) (((packetLen & 7) << 5) + 0x1F);
packet[6] = (byte) 0xFC;
}
}