package android.media;
import java.io.InputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import android.media.MediaCodec.BufferInfo;
import android.util.Log;
public final class AmrInputStream extends InputStream {
private final static String TAG = "AmrInputStream";
private final static int SAMPLES_PER_FRAME = 8000 * 20 / 1000;
MediaCodec mCodec;
BufferInfo mInfo;
boolean mSawOutputEOS;
boolean mSawInputEOS;
private InputStream mInputStream;
private final byte[] mBuf = new byte[SAMPLES_PER_FRAME * 2];
private int mBufIn = 0;
private int mBufOut = 0;
private byte[] mOneByte = new byte[1];
public AmrInputStream(InputStream inputStream) {
Log.w(TAG, "@@@@ AmrInputStream is not a public API @@@@");
mInputStream = inputStream;
MediaFormat format = new MediaFormat();
format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AMR_NB);
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 8000);
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
format.setInteger(MediaFormat.KEY_BIT_RATE, 12200);
MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
String name = mcl.findEncoderForFormat(format);
if (name != null) {
try {
mCodec = MediaCodec.createByCodecName(name);
mCodec.configure(format,
null ,
null ,
MediaCodec.CONFIGURE_FLAG_ENCODE);
mCodec.start();
} catch (IOException e) {
if (mCodec != null) {
mCodec.release();
}
mCodec = null;
}
}
mInfo = new BufferInfo();
}
@Override
public int read() throws IOException {
int rtn = read(mOneByte, 0, 1);
return rtn == 1 ? (0xff & mOneByte[0]) : -1;
}
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public int read(byte[] b, int offset, int length) throws IOException {
if (mCodec == null) {
throw new IllegalStateException("not open");
}
if (mBufOut >= mBufIn && !mSawOutputEOS) {
mBufOut = 0;
mBufIn = 0;
while (!mSawInputEOS) {
int index = mCodec.dequeueInputBuffer(0);
if (index < 0) {
break;
} else {
int numRead;
for (numRead = 0; numRead < SAMPLES_PER_FRAME * 2; ) {
int n = mInputStream.read(mBuf, numRead, SAMPLES_PER_FRAME * 2 - numRead);
if (n == -1) {
mSawInputEOS = true;
break;
}
numRead += n;
}
ByteBuffer buf = mCodec.getInputBuffer(index);
buf.put(mBuf, 0, numRead);
mCodec.queueInputBuffer(index,
0 ,
numRead,
0 ,
mSawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0 );
}
}
int index = mCodec.dequeueOutputBuffer(mInfo, 0);
if (index >= 0) {
mBufIn = mInfo.size;
ByteBuffer out = mCodec.getOutputBuffer(index);
out.get(mBuf, 0 , mBufIn );
mCodec.releaseOutputBuffer(index, false );
if ((mInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
mSawOutputEOS = true;
}
}
}
if (mBufOut < mBufIn) {
if (length > mBufIn - mBufOut) {
length = mBufIn - mBufOut;
}
System.arraycopy(mBuf, mBufOut, b, offset, length);
mBufOut += length;
return length;
}
if (mSawInputEOS && mSawOutputEOS) {
return -1;
}
return 0;
}
@Override
public void close() throws IOException {
try {
if (mInputStream != null) {
mInputStream.close();
}
} finally {
mInputStream = null;
try {
if (mCodec != null) {
mCodec.release();
}
} finally {
mCodec = null;
}
}
}
@Override
protected void finalize() throws Throwable {
if (mCodec != null) {
Log.w(TAG, "AmrInputStream wasn't closed");
mCodec.release();
}
}
}