Loading media/java/android/media/AmrInputStream.java +115 −58 Original line number Original line Diff line number Diff line Loading @@ -18,29 +18,30 @@ package android.media; import java.io.InputStream; import java.io.InputStream; import java.io.IOException; import java.io.IOException; import java.nio.ByteBuffer; import android.media.MediaCodec.BufferInfo; import android.util.Log; /** /** * AmrInputStream * AmrInputStream * @hide * @hide */ */ public final class AmrInputStream extends InputStream public final class AmrInputStream extends InputStream { { static { System.loadLibrary("media_jni"); } private final static String TAG = "AmrInputStream"; private final static String TAG = "AmrInputStream"; // frame is 20 msec at 8.000 khz // frame is 20 msec at 8.000 khz private final static int SAMPLES_PER_FRAME = 8000 * 20 / 1000; private final static int SAMPLES_PER_FRAME = 8000 * 20 / 1000; MediaCodec mCodec; BufferInfo mInfo; boolean mSawOutputEOS; boolean mSawInputEOS; // pcm input stream // pcm input stream private InputStream mInputStream; private InputStream mInputStream; // native handle private long mGae; // result amr stream // result amr stream private final byte[] mBuf = new byte[SAMPLES_PER_FRAME * 2]; private final byte[] mBuf = new byte[SAMPLES_PER_FRAME * 2]; private int mBufIn = 0; private int mBufIn = 0; Loading @@ -55,8 +56,31 @@ public final class AmrInputStream extends InputStream */ */ public AmrInputStream(InputStream inputStream) { public AmrInputStream(InputStream inputStream) { mInputStream = inputStream; mInputStream = inputStream; mGae = GsmAmrEncoderNew(); GsmAmrEncoderInitialize(mGae); 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 /* surface */, null /* crypto */, MediaCodec.CONFIGURE_FLAG_ENCODE); mCodec.start(); } catch (IOException e) { if (mCodec != null) { mCodec.release(); } mCodec = null; } } mInfo = new BufferInfo(); } } @Override @Override Loading @@ -72,67 +96,100 @@ public final class AmrInputStream extends InputStream @Override @Override public int read(byte[] b, int offset, int length) throws IOException { public int read(byte[] b, int offset, int length) throws IOException { if (mGae == 0) throw new IllegalStateException("not open"); if (mCodec == null) { throw new IllegalStateException("not open"); } // local buffer of amr encoded audio empty if (mBufOut >= mBufIn && !mSawOutputEOS) { if (mBufOut >= mBufIn) { // no data left in buffer, refill it // reset the buffer mBufOut = 0; mBufOut = 0; mBufIn = 0; mBufIn = 0; // fetch a 20 msec frame of pcm // first push as much data into the encoder as possible for (int i = 0; i < SAMPLES_PER_FRAME * 2; ) { while (!mSawInputEOS) { int n = mInputStream.read(mBuf, i, SAMPLES_PER_FRAME * 2 - i); int index = mCodec.dequeueInputBuffer(0); if (n == -1) return -1; if (index < 0) { i += n; // no input buffer currently available 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 /* offset */, numRead, 0 /* presentationTimeUs */, mSawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0 /* flags */); } } } // encode it // now read encoded data from the encoder (blocking, since we just filled up the mBufIn = GsmAmrEncoderEncode(mGae, mBuf, 0, mBuf, 0); // encoder's input with data it should be able to output at least one buffer) while (true) { int index = mCodec.dequeueOutputBuffer(mInfo, -1); if (index >= 0) { mBufIn = mInfo.size; ByteBuffer out = mCodec.getOutputBuffer(index); out.get(mBuf, 0 /* offset */, mBufIn /* length */); mCodec.releaseOutputBuffer(index, false /* render */); if ((mInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { mSawOutputEOS = true; } break; } } } } // return encoded audio to user if (mBufOut < mBufIn) { if (length > mBufIn - mBufOut) length = mBufIn - mBufOut; // there is data in the buffer if (length > mBufIn - mBufOut) { length = mBufIn - mBufOut; } System.arraycopy(mBuf, mBufOut, b, offset, length); System.arraycopy(mBuf, mBufOut, b, offset, length); mBufOut += length; mBufOut += length; return length; return length; } } if (mSawInputEOS && mSawOutputEOS) { // no more data available in buffer, codec or input stream return -1; } // caller should try again return 0; } @Override @Override public void close() throws IOException { public void close() throws IOException { try { try { if (mInputStream != null) mInputStream.close(); if (mInputStream != null) { mInputStream.close(); } } finally { } finally { mInputStream = null; mInputStream = null; try { try { if (mGae != 0) GsmAmrEncoderCleanup(mGae); if (mCodec != null) { } finally { mCodec.release(); try { if (mGae != 0) GsmAmrEncoderDelete(mGae); } finally { mGae = 0; } } } finally { mCodec = null; } } } } } } @Override @Override protected void finalize() throws Throwable { protected void finalize() throws Throwable { if (mGae != 0) { if (mCodec != null) { close(); Log.w(TAG, "AmrInputStream wasn't closed"); throw new IllegalStateException("someone forgot to close AmrInputStream"); mCodec.release(); } } } } // // AudioRecord JNI interface // private static native long GsmAmrEncoderNew(); private static native void GsmAmrEncoderInitialize(long gae); private static native int GsmAmrEncoderEncode(long gae, byte[] pcm, int pcmOffset, byte[] amr, int amrOffset) throws IOException; private static native void GsmAmrEncoderCleanup(long gae); private static native void GsmAmrEncoderDelete(long gae); } } media/jni/Android.mk +0 −6 Original line number Original line Diff line number Diff line Loading @@ -2,7 +2,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ LOCAL_SRC_FILES:= \ android_media_AmrInputStream.cpp \ android_media_ExifInterface.cpp \ android_media_ExifInterface.cpp \ android_media_ImageWriter.cpp \ android_media_ImageWriter.cpp \ android_media_ImageReader.cpp \ android_media_ImageReader.cpp \ Loading Loading @@ -46,11 +45,9 @@ LOCAL_SHARED_LIBRARIES := \ libusbhost \ libusbhost \ libexif \ libexif \ libpiex \ libpiex \ libstagefright_amrnb_common \ libandroidfw libandroidfw LOCAL_STATIC_LIBRARIES := \ LOCAL_STATIC_LIBRARIES := \ libstagefright_amrnbenc LOCAL_C_INCLUDES += \ LOCAL_C_INCLUDES += \ external/libexif/ \ external/libexif/ \ Loading @@ -60,9 +57,6 @@ LOCAL_C_INCLUDES += \ frameworks/base/libs/hwui \ frameworks/base/libs/hwui \ frameworks/av/media/libmedia \ frameworks/av/media/libmedia \ frameworks/av/media/libstagefright \ frameworks/av/media/libstagefright \ frameworks/av/media/libstagefright/codecs/amrnb/enc/src \ frameworks/av/media/libstagefright/codecs/amrnb/common \ frameworks/av/media/libstagefright/codecs/amrnb/common/include \ frameworks/av/media/mtp \ frameworks/av/media/mtp \ frameworks/native/include/media/openmax \ frameworks/native/include/media/openmax \ $(call include-path-for, libhardware)/hardware \ $(call include-path-for, libhardware)/hardware \ Loading media/jni/android_media_AmrInputStream.cppdeleted 100644 → 0 +0 −137 Original line number Original line Diff line number Diff line /* ** ** Copyright 2007, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #define LOG_TAG "AmrInputStream" #include "utils/Log.h" #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" #include "gsmamr_enc.h" // ---------------------------------------------------------------------------- using namespace android; // Corresponds to max bit rate of 12.2 kbps. static const int MAX_OUTPUT_BUFFER_SIZE = 32; static const int FRAME_DURATION_MS = 20; static const int SAMPLING_RATE_HZ = 8000; static const int SAMPLES_PER_FRAME = ((SAMPLING_RATE_HZ * FRAME_DURATION_MS) / 1000); static const int BYTES_PER_SAMPLE = 2; // Assume 16-bit PCM samples static const int BYTES_PER_FRAME = (SAMPLES_PER_FRAME * BYTES_PER_SAMPLE); struct GsmAmrEncoderState { GsmAmrEncoderState() : mEncState(NULL), mSidState(NULL), mLastModeUsed(0) { } ~GsmAmrEncoderState() {} void* mEncState; void* mSidState; int32_t mLastModeUsed; }; static jlong android_media_AmrInputStream_GsmAmrEncoderNew (JNIEnv *env, jclass /* clazz */) { GsmAmrEncoderState* gae = new GsmAmrEncoderState(); if (gae == NULL) { jniThrowRuntimeException(env, "Out of memory"); } return (jlong)gae; } static void android_media_AmrInputStream_GsmAmrEncoderInitialize (JNIEnv *env, jclass /* clazz */, jlong gae) { GsmAmrEncoderState *state = (GsmAmrEncoderState *) gae; int32_t nResult = AMREncodeInit(&state->mEncState, &state->mSidState, false); if (nResult != OK) { jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "GsmAmrEncoder initialization failed %d", nResult); } } static jint android_media_AmrInputStream_GsmAmrEncoderEncode (JNIEnv *env, jclass /* clazz */, jlong gae, jbyteArray pcm, jint pcmOffset, jbyteArray amr, jint amrOffset) { jbyte inBuf[BYTES_PER_FRAME]; jbyte outBuf[MAX_OUTPUT_BUFFER_SIZE]; env->GetByteArrayRegion(pcm, pcmOffset, sizeof(inBuf), inBuf); GsmAmrEncoderState *state = (GsmAmrEncoderState *) gae; int32_t length = AMREncode(state->mEncState, state->mSidState, (Mode) MR122, (int16_t *) inBuf, (unsigned char *) outBuf, (Frame_Type_3GPP*) &state->mLastModeUsed, AMR_TX_WMF); if (length < 0) { jniThrowExceptionFmt(env, "java/io/IOException", "Failed to encode a frame with error code: %d", length); return (jint)-1; } // The 1st byte of PV AMR frames are WMF (Wireless Multimedia Forum) // bitpacked, i.e.; // [P(4) + FT(4)]. Q=1 for good frame, P=padding bit, 0 // Here we are converting the header to be as specified in Section 5.3 of // RFC 3267 (AMR storage format) i.e. // [P(1) + FT(4) + Q(1) + P(2)]. if (length > 0) { outBuf[0] = (outBuf[0] << 3) | 0x4; } env->SetByteArrayRegion(amr, amrOffset, length, outBuf); return (jint)length; } static void android_media_AmrInputStream_GsmAmrEncoderCleanup (JNIEnv* /* env */, jclass /* clazz */, jlong gae) { GsmAmrEncoderState *state = (GsmAmrEncoderState *) gae; AMREncodeExit(&state->mEncState, &state->mSidState); state->mEncState = NULL; state->mSidState = NULL; } static void android_media_AmrInputStream_GsmAmrEncoderDelete (JNIEnv* /* env */, jclass /* clazz */, jlong gae) { delete (GsmAmrEncoderState*)gae; } // ---------------------------------------------------------------------------- static const JNINativeMethod gMethods[] = { {"GsmAmrEncoderNew", "()J", (void*)android_media_AmrInputStream_GsmAmrEncoderNew}, {"GsmAmrEncoderInitialize", "(J)V", (void*)android_media_AmrInputStream_GsmAmrEncoderInitialize}, {"GsmAmrEncoderEncode", "(J[BI[BI)I", (void*)android_media_AmrInputStream_GsmAmrEncoderEncode}, {"GsmAmrEncoderCleanup", "(J)V", (void*)android_media_AmrInputStream_GsmAmrEncoderCleanup}, {"GsmAmrEncoderDelete", "(J)V", (void*)android_media_AmrInputStream_GsmAmrEncoderDelete}, }; int register_android_media_AmrInputStream(JNIEnv *env) { const char* const kClassPathName = "android/media/AmrInputStream"; return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); } media/jni/android_media_MediaPlayer.cpp +0 −6 Original line number Original line Diff line number Diff line Loading @@ -1106,7 +1106,6 @@ extern int register_android_media_MediaScanner(JNIEnv *env); extern int register_android_media_MediaSync(JNIEnv *env); extern int register_android_media_MediaSync(JNIEnv *env); extern int register_android_media_ResampleInputStream(JNIEnv *env); extern int register_android_media_ResampleInputStream(JNIEnv *env); extern int register_android_media_MediaProfiles(JNIEnv *env); extern int register_android_media_MediaProfiles(JNIEnv *env); extern int register_android_media_AmrInputStream(JNIEnv *env); extern int register_android_mtp_MtpDatabase(JNIEnv *env); extern int register_android_mtp_MtpDatabase(JNIEnv *env); extern int register_android_mtp_MtpDevice(JNIEnv *env); extern int register_android_mtp_MtpDevice(JNIEnv *env); extern int register_android_mtp_MtpServer(JNIEnv *env); extern int register_android_mtp_MtpServer(JNIEnv *env); Loading Loading @@ -1152,11 +1151,6 @@ jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) goto bail; goto bail; } } if (register_android_media_AmrInputStream(env) < 0) { ALOGE("ERROR: AmrInputStream native registration failed\n"); goto bail; } if (register_android_media_ResampleInputStream(env) < 0) { if (register_android_media_ResampleInputStream(env) < 0) { ALOGE("ERROR: ResampleInputStream native registration failed\n"); ALOGE("ERROR: ResampleInputStream native registration failed\n"); goto bail; goto bail; Loading Loading
media/java/android/media/AmrInputStream.java +115 −58 Original line number Original line Diff line number Diff line Loading @@ -18,29 +18,30 @@ package android.media; import java.io.InputStream; import java.io.InputStream; import java.io.IOException; import java.io.IOException; import java.nio.ByteBuffer; import android.media.MediaCodec.BufferInfo; import android.util.Log; /** /** * AmrInputStream * AmrInputStream * @hide * @hide */ */ public final class AmrInputStream extends InputStream public final class AmrInputStream extends InputStream { { static { System.loadLibrary("media_jni"); } private final static String TAG = "AmrInputStream"; private final static String TAG = "AmrInputStream"; // frame is 20 msec at 8.000 khz // frame is 20 msec at 8.000 khz private final static int SAMPLES_PER_FRAME = 8000 * 20 / 1000; private final static int SAMPLES_PER_FRAME = 8000 * 20 / 1000; MediaCodec mCodec; BufferInfo mInfo; boolean mSawOutputEOS; boolean mSawInputEOS; // pcm input stream // pcm input stream private InputStream mInputStream; private InputStream mInputStream; // native handle private long mGae; // result amr stream // result amr stream private final byte[] mBuf = new byte[SAMPLES_PER_FRAME * 2]; private final byte[] mBuf = new byte[SAMPLES_PER_FRAME * 2]; private int mBufIn = 0; private int mBufIn = 0; Loading @@ -55,8 +56,31 @@ public final class AmrInputStream extends InputStream */ */ public AmrInputStream(InputStream inputStream) { public AmrInputStream(InputStream inputStream) { mInputStream = inputStream; mInputStream = inputStream; mGae = GsmAmrEncoderNew(); GsmAmrEncoderInitialize(mGae); 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 /* surface */, null /* crypto */, MediaCodec.CONFIGURE_FLAG_ENCODE); mCodec.start(); } catch (IOException e) { if (mCodec != null) { mCodec.release(); } mCodec = null; } } mInfo = new BufferInfo(); } } @Override @Override Loading @@ -72,67 +96,100 @@ public final class AmrInputStream extends InputStream @Override @Override public int read(byte[] b, int offset, int length) throws IOException { public int read(byte[] b, int offset, int length) throws IOException { if (mGae == 0) throw new IllegalStateException("not open"); if (mCodec == null) { throw new IllegalStateException("not open"); } // local buffer of amr encoded audio empty if (mBufOut >= mBufIn && !mSawOutputEOS) { if (mBufOut >= mBufIn) { // no data left in buffer, refill it // reset the buffer mBufOut = 0; mBufOut = 0; mBufIn = 0; mBufIn = 0; // fetch a 20 msec frame of pcm // first push as much data into the encoder as possible for (int i = 0; i < SAMPLES_PER_FRAME * 2; ) { while (!mSawInputEOS) { int n = mInputStream.read(mBuf, i, SAMPLES_PER_FRAME * 2 - i); int index = mCodec.dequeueInputBuffer(0); if (n == -1) return -1; if (index < 0) { i += n; // no input buffer currently available 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 /* offset */, numRead, 0 /* presentationTimeUs */, mSawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0 /* flags */); } } } // encode it // now read encoded data from the encoder (blocking, since we just filled up the mBufIn = GsmAmrEncoderEncode(mGae, mBuf, 0, mBuf, 0); // encoder's input with data it should be able to output at least one buffer) while (true) { int index = mCodec.dequeueOutputBuffer(mInfo, -1); if (index >= 0) { mBufIn = mInfo.size; ByteBuffer out = mCodec.getOutputBuffer(index); out.get(mBuf, 0 /* offset */, mBufIn /* length */); mCodec.releaseOutputBuffer(index, false /* render */); if ((mInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { mSawOutputEOS = true; } break; } } } } // return encoded audio to user if (mBufOut < mBufIn) { if (length > mBufIn - mBufOut) length = mBufIn - mBufOut; // there is data in the buffer if (length > mBufIn - mBufOut) { length = mBufIn - mBufOut; } System.arraycopy(mBuf, mBufOut, b, offset, length); System.arraycopy(mBuf, mBufOut, b, offset, length); mBufOut += length; mBufOut += length; return length; return length; } } if (mSawInputEOS && mSawOutputEOS) { // no more data available in buffer, codec or input stream return -1; } // caller should try again return 0; } @Override @Override public void close() throws IOException { public void close() throws IOException { try { try { if (mInputStream != null) mInputStream.close(); if (mInputStream != null) { mInputStream.close(); } } finally { } finally { mInputStream = null; mInputStream = null; try { try { if (mGae != 0) GsmAmrEncoderCleanup(mGae); if (mCodec != null) { } finally { mCodec.release(); try { if (mGae != 0) GsmAmrEncoderDelete(mGae); } finally { mGae = 0; } } } finally { mCodec = null; } } } } } } @Override @Override protected void finalize() throws Throwable { protected void finalize() throws Throwable { if (mGae != 0) { if (mCodec != null) { close(); Log.w(TAG, "AmrInputStream wasn't closed"); throw new IllegalStateException("someone forgot to close AmrInputStream"); mCodec.release(); } } } } // // AudioRecord JNI interface // private static native long GsmAmrEncoderNew(); private static native void GsmAmrEncoderInitialize(long gae); private static native int GsmAmrEncoderEncode(long gae, byte[] pcm, int pcmOffset, byte[] amr, int amrOffset) throws IOException; private static native void GsmAmrEncoderCleanup(long gae); private static native void GsmAmrEncoderDelete(long gae); } }
media/jni/Android.mk +0 −6 Original line number Original line Diff line number Diff line Loading @@ -2,7 +2,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ LOCAL_SRC_FILES:= \ android_media_AmrInputStream.cpp \ android_media_ExifInterface.cpp \ android_media_ExifInterface.cpp \ android_media_ImageWriter.cpp \ android_media_ImageWriter.cpp \ android_media_ImageReader.cpp \ android_media_ImageReader.cpp \ Loading Loading @@ -46,11 +45,9 @@ LOCAL_SHARED_LIBRARIES := \ libusbhost \ libusbhost \ libexif \ libexif \ libpiex \ libpiex \ libstagefright_amrnb_common \ libandroidfw libandroidfw LOCAL_STATIC_LIBRARIES := \ LOCAL_STATIC_LIBRARIES := \ libstagefright_amrnbenc LOCAL_C_INCLUDES += \ LOCAL_C_INCLUDES += \ external/libexif/ \ external/libexif/ \ Loading @@ -60,9 +57,6 @@ LOCAL_C_INCLUDES += \ frameworks/base/libs/hwui \ frameworks/base/libs/hwui \ frameworks/av/media/libmedia \ frameworks/av/media/libmedia \ frameworks/av/media/libstagefright \ frameworks/av/media/libstagefright \ frameworks/av/media/libstagefright/codecs/amrnb/enc/src \ frameworks/av/media/libstagefright/codecs/amrnb/common \ frameworks/av/media/libstagefright/codecs/amrnb/common/include \ frameworks/av/media/mtp \ frameworks/av/media/mtp \ frameworks/native/include/media/openmax \ frameworks/native/include/media/openmax \ $(call include-path-for, libhardware)/hardware \ $(call include-path-for, libhardware)/hardware \ Loading
media/jni/android_media_AmrInputStream.cppdeleted 100644 → 0 +0 −137 Original line number Original line Diff line number Diff line /* ** ** Copyright 2007, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #define LOG_TAG "AmrInputStream" #include "utils/Log.h" #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" #include "gsmamr_enc.h" // ---------------------------------------------------------------------------- using namespace android; // Corresponds to max bit rate of 12.2 kbps. static const int MAX_OUTPUT_BUFFER_SIZE = 32; static const int FRAME_DURATION_MS = 20; static const int SAMPLING_RATE_HZ = 8000; static const int SAMPLES_PER_FRAME = ((SAMPLING_RATE_HZ * FRAME_DURATION_MS) / 1000); static const int BYTES_PER_SAMPLE = 2; // Assume 16-bit PCM samples static const int BYTES_PER_FRAME = (SAMPLES_PER_FRAME * BYTES_PER_SAMPLE); struct GsmAmrEncoderState { GsmAmrEncoderState() : mEncState(NULL), mSidState(NULL), mLastModeUsed(0) { } ~GsmAmrEncoderState() {} void* mEncState; void* mSidState; int32_t mLastModeUsed; }; static jlong android_media_AmrInputStream_GsmAmrEncoderNew (JNIEnv *env, jclass /* clazz */) { GsmAmrEncoderState* gae = new GsmAmrEncoderState(); if (gae == NULL) { jniThrowRuntimeException(env, "Out of memory"); } return (jlong)gae; } static void android_media_AmrInputStream_GsmAmrEncoderInitialize (JNIEnv *env, jclass /* clazz */, jlong gae) { GsmAmrEncoderState *state = (GsmAmrEncoderState *) gae; int32_t nResult = AMREncodeInit(&state->mEncState, &state->mSidState, false); if (nResult != OK) { jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "GsmAmrEncoder initialization failed %d", nResult); } } static jint android_media_AmrInputStream_GsmAmrEncoderEncode (JNIEnv *env, jclass /* clazz */, jlong gae, jbyteArray pcm, jint pcmOffset, jbyteArray amr, jint amrOffset) { jbyte inBuf[BYTES_PER_FRAME]; jbyte outBuf[MAX_OUTPUT_BUFFER_SIZE]; env->GetByteArrayRegion(pcm, pcmOffset, sizeof(inBuf), inBuf); GsmAmrEncoderState *state = (GsmAmrEncoderState *) gae; int32_t length = AMREncode(state->mEncState, state->mSidState, (Mode) MR122, (int16_t *) inBuf, (unsigned char *) outBuf, (Frame_Type_3GPP*) &state->mLastModeUsed, AMR_TX_WMF); if (length < 0) { jniThrowExceptionFmt(env, "java/io/IOException", "Failed to encode a frame with error code: %d", length); return (jint)-1; } // The 1st byte of PV AMR frames are WMF (Wireless Multimedia Forum) // bitpacked, i.e.; // [P(4) + FT(4)]. Q=1 for good frame, P=padding bit, 0 // Here we are converting the header to be as specified in Section 5.3 of // RFC 3267 (AMR storage format) i.e. // [P(1) + FT(4) + Q(1) + P(2)]. if (length > 0) { outBuf[0] = (outBuf[0] << 3) | 0x4; } env->SetByteArrayRegion(amr, amrOffset, length, outBuf); return (jint)length; } static void android_media_AmrInputStream_GsmAmrEncoderCleanup (JNIEnv* /* env */, jclass /* clazz */, jlong gae) { GsmAmrEncoderState *state = (GsmAmrEncoderState *) gae; AMREncodeExit(&state->mEncState, &state->mSidState); state->mEncState = NULL; state->mSidState = NULL; } static void android_media_AmrInputStream_GsmAmrEncoderDelete (JNIEnv* /* env */, jclass /* clazz */, jlong gae) { delete (GsmAmrEncoderState*)gae; } // ---------------------------------------------------------------------------- static const JNINativeMethod gMethods[] = { {"GsmAmrEncoderNew", "()J", (void*)android_media_AmrInputStream_GsmAmrEncoderNew}, {"GsmAmrEncoderInitialize", "(J)V", (void*)android_media_AmrInputStream_GsmAmrEncoderInitialize}, {"GsmAmrEncoderEncode", "(J[BI[BI)I", (void*)android_media_AmrInputStream_GsmAmrEncoderEncode}, {"GsmAmrEncoderCleanup", "(J)V", (void*)android_media_AmrInputStream_GsmAmrEncoderCleanup}, {"GsmAmrEncoderDelete", "(J)V", (void*)android_media_AmrInputStream_GsmAmrEncoderDelete}, }; int register_android_media_AmrInputStream(JNIEnv *env) { const char* const kClassPathName = "android/media/AmrInputStream"; return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); }
media/jni/android_media_MediaPlayer.cpp +0 −6 Original line number Original line Diff line number Diff line Loading @@ -1106,7 +1106,6 @@ extern int register_android_media_MediaScanner(JNIEnv *env); extern int register_android_media_MediaSync(JNIEnv *env); extern int register_android_media_MediaSync(JNIEnv *env); extern int register_android_media_ResampleInputStream(JNIEnv *env); extern int register_android_media_ResampleInputStream(JNIEnv *env); extern int register_android_media_MediaProfiles(JNIEnv *env); extern int register_android_media_MediaProfiles(JNIEnv *env); extern int register_android_media_AmrInputStream(JNIEnv *env); extern int register_android_mtp_MtpDatabase(JNIEnv *env); extern int register_android_mtp_MtpDatabase(JNIEnv *env); extern int register_android_mtp_MtpDevice(JNIEnv *env); extern int register_android_mtp_MtpDevice(JNIEnv *env); extern int register_android_mtp_MtpServer(JNIEnv *env); extern int register_android_mtp_MtpServer(JNIEnv *env); Loading Loading @@ -1152,11 +1151,6 @@ jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) goto bail; goto bail; } } if (register_android_media_AmrInputStream(env) < 0) { ALOGE("ERROR: AmrInputStream native registration failed\n"); goto bail; } if (register_android_media_ResampleInputStream(env) < 0) { if (register_android_media_ResampleInputStream(env) < 0) { ALOGE("ERROR: ResampleInputStream native registration failed\n"); ALOGE("ERROR: ResampleInputStream native registration failed\n"); goto bail; goto bail; Loading