From e4d9a01bfc7451afff1ed399a5801c7aa2af2831 Mon Sep 17 00:00:00 2001 From: Dan Morrill Date: Thu, 28 Mar 2013 18:10:43 -0700 Subject: Phase 1 of refactoring SystemServer. SystemServer is currently a monolithic class that brings up key system services. This change is the first phase of refactoring it to be more configurable. Specifically, it adds a set of on/off switches used to control startup of individual services. Future plans include finer grained controls and a more explicit and consistent startup sequence for these services. Change-Id: I7299f5ce7d7b74a34eb56dffb788366fbc058532 --- media/jni/soundpool/Android.mk | 2 +- media/jni/soundpool/android_media_SoundPool.cpp | 327 --------------------- .../android_media_SoundPool_SoundPoolImpl.cpp | 327 +++++++++++++++++++++ 3 files changed, 328 insertions(+), 328 deletions(-) delete mode 100644 media/jni/soundpool/android_media_SoundPool.cpp create mode 100644 media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp (limited to 'media/jni') diff --git a/media/jni/soundpool/Android.mk b/media/jni/soundpool/Android.mk index 9b11bfa..1286482 100644 --- a/media/jni/soundpool/Android.mk +++ b/media/jni/soundpool/Android.mk @@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - android_media_SoundPool.cpp + android_media_SoundPool_SoundPoolImpl.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp deleted file mode 100644 index 9658856..0000000 --- a/media/jni/soundpool/android_media_SoundPool.cpp +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -#include - -//#define LOG_NDEBUG 0 -#define LOG_TAG "SoundPool-JNI" - -#include -#include -#include -#include -#include - -using namespace android; - -static struct fields_t { - jfieldID mNativeContext; - jmethodID mPostEvent; - jclass mSoundPoolClass; -} fields; - -static inline SoundPool* MusterSoundPool(JNIEnv *env, jobject thiz) { - return (SoundPool*)env->GetIntField(thiz, fields.mNativeContext); -} - -// ---------------------------------------------------------------------------- -static int -android_media_SoundPool_load_URL(JNIEnv *env, jobject thiz, jstring path, jint priority) -{ - ALOGV("android_media_SoundPool_load_URL"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (path == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", NULL); - return 0; - } - const char* s = env->GetStringUTFChars(path, NULL); - int id = ap->load(s, priority); - env->ReleaseStringUTFChars(path, s); - return id; -} - -static int -android_media_SoundPool_load_FD(JNIEnv *env, jobject thiz, jobject fileDescriptor, - jlong offset, jlong length, jint priority) -{ - ALOGV("android_media_SoundPool_load_FD"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return 0; - return ap->load(jniGetFDFromFileDescriptor(env, fileDescriptor), - int64_t(offset), int64_t(length), int(priority)); -} - -static bool -android_media_SoundPool_unload(JNIEnv *env, jobject thiz, jint sampleID) { - ALOGV("android_media_SoundPool_unload\n"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return 0; - return ap->unload(sampleID); -} - -static int -android_media_SoundPool_play(JNIEnv *env, jobject thiz, jint sampleID, - jfloat leftVolume, jfloat rightVolume, jint priority, jint loop, - jfloat rate) -{ - ALOGV("android_media_SoundPool_play\n"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return 0; - return ap->play(sampleID, leftVolume, rightVolume, priority, loop, rate); -} - -static void -android_media_SoundPool_pause(JNIEnv *env, jobject thiz, jint channelID) -{ - ALOGV("android_media_SoundPool_pause"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; - ap->pause(channelID); -} - -static void -android_media_SoundPool_resume(JNIEnv *env, jobject thiz, jint channelID) -{ - ALOGV("android_media_SoundPool_resume"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; - ap->resume(channelID); -} - -static void -android_media_SoundPool_autoPause(JNIEnv *env, jobject thiz) -{ - ALOGV("android_media_SoundPool_autoPause"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; - ap->autoPause(); -} - -static void -android_media_SoundPool_autoResume(JNIEnv *env, jobject thiz) -{ - ALOGV("android_media_SoundPool_autoResume"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; - ap->autoResume(); -} - -static void -android_media_SoundPool_stop(JNIEnv *env, jobject thiz, jint channelID) -{ - ALOGV("android_media_SoundPool_stop"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; - ap->stop(channelID); -} - -static void -android_media_SoundPool_setVolume(JNIEnv *env, jobject thiz, jint channelID, - float leftVolume, float rightVolume) -{ - ALOGV("android_media_SoundPool_setVolume"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; - ap->setVolume(channelID, leftVolume, rightVolume); -} - -static void -android_media_SoundPool_setPriority(JNIEnv *env, jobject thiz, jint channelID, - int priority) -{ - ALOGV("android_media_SoundPool_setPriority"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; - ap->setPriority(channelID, priority); -} - -static void -android_media_SoundPool_setLoop(JNIEnv *env, jobject thiz, jint channelID, - int loop) -{ - ALOGV("android_media_SoundPool_setLoop"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; - ap->setLoop(channelID, loop); -} - -static void -android_media_SoundPool_setRate(JNIEnv *env, jobject thiz, jint channelID, - float rate) -{ - ALOGV("android_media_SoundPool_setRate"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; - ap->setRate(channelID, rate); -} - -static void android_media_callback(SoundPoolEvent event, SoundPool* soundPool, void* user) -{ - ALOGV("callback: (%d, %d, %d, %p, %p)", event.mMsg, event.mArg1, event.mArg2, soundPool, user); - JNIEnv *env = AndroidRuntime::getJNIEnv(); - env->CallStaticVoidMethod(fields.mSoundPoolClass, fields.mPostEvent, user, event.mMsg, event.mArg1, event.mArg2, NULL); -} - -static jint -android_media_SoundPool_native_setup(JNIEnv *env, jobject thiz, jobject weakRef, jint maxChannels, jint streamType, jint srcQuality) -{ - ALOGV("android_media_SoundPool_native_setup"); - SoundPool *ap = new SoundPool(maxChannels, (audio_stream_type_t) streamType, srcQuality); - if (ap == NULL) { - return -1; - } - - // save pointer to SoundPool C++ object in opaque field in Java object - env->SetIntField(thiz, fields.mNativeContext, (int)ap); - - // set callback with weak reference - jobject globalWeakRef = env->NewGlobalRef(weakRef); - ap->setCallback(android_media_callback, globalWeakRef); - return 0; -} - -static void -android_media_SoundPool_release(JNIEnv *env, jobject thiz) -{ - ALOGV("android_media_SoundPool_release"); - SoundPool *ap = MusterSoundPool(env, thiz); - if (ap != NULL) { - - // release weak reference - jobject weakRef = (jobject) ap->getUserData(); - if (weakRef != NULL) { - env->DeleteGlobalRef(weakRef); - } - - // clear callback and native context - ap->setCallback(NULL, NULL); - env->SetIntField(thiz, fields.mNativeContext, 0); - delete ap; - } -} - -// ---------------------------------------------------------------------------- - -// Dalvik VM type signatures -static JNINativeMethod gMethods[] = { - { "_load", - "(Ljava/lang/String;I)I", - (void *)android_media_SoundPool_load_URL - }, - { "_load", - "(Ljava/io/FileDescriptor;JJI)I", - (void *)android_media_SoundPool_load_FD - }, - { "unload", - "(I)Z", - (void *)android_media_SoundPool_unload - }, - { "play", - "(IFFIIF)I", - (void *)android_media_SoundPool_play - }, - { "pause", - "(I)V", - (void *)android_media_SoundPool_pause - }, - { "resume", - "(I)V", - (void *)android_media_SoundPool_resume - }, - { "autoPause", - "()V", - (void *)android_media_SoundPool_autoPause - }, - { "autoResume", - "()V", - (void *)android_media_SoundPool_autoResume - }, - { "stop", - "(I)V", - (void *)android_media_SoundPool_stop - }, - { "setVolume", - "(IFF)V", - (void *)android_media_SoundPool_setVolume - }, - { "setPriority", - "(II)V", - (void *)android_media_SoundPool_setPriority - }, - { "setLoop", - "(II)V", - (void *)android_media_SoundPool_setLoop - }, - { "setRate", - "(IF)V", - (void *)android_media_SoundPool_setRate - }, - { "native_setup", - "(Ljava/lang/Object;III)I", - (void*)android_media_SoundPool_native_setup - }, - { "release", - "()V", - (void*)android_media_SoundPool_release - } -}; - -static const char* const kClassPathName = "android/media/SoundPool"; - -jint JNI_OnLoad(JavaVM* vm, void* reserved) -{ - JNIEnv* env = NULL; - jint result = -1; - jclass clazz; - - if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { - ALOGE("ERROR: GetEnv failed\n"); - goto bail; - } - assert(env != NULL); - - clazz = env->FindClass(kClassPathName); - if (clazz == NULL) { - ALOGE("Can't find %s", kClassPathName); - goto bail; - } - - fields.mNativeContext = env->GetFieldID(clazz, "mNativeContext", "I"); - if (fields.mNativeContext == NULL) { - ALOGE("Can't find SoundPool.mNativeContext"); - goto bail; - } - - fields.mPostEvent = env->GetStaticMethodID(clazz, "postEventFromNative", - "(Ljava/lang/Object;IIILjava/lang/Object;)V"); - if (fields.mPostEvent == NULL) { - ALOGE("Can't find android/media/SoundPool.postEventFromNative"); - goto bail; - } - - // create a reference to class. Technically, we're leaking this reference - // since it's a static object. - fields.mSoundPoolClass = (jclass) env->NewGlobalRef(clazz); - - if (AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)) < 0) - goto bail; - - /* success -- return valid version number */ - result = JNI_VERSION_1_4; - -bail: - return result; -} diff --git a/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp b/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp new file mode 100644 index 0000000..2604850 --- /dev/null +++ b/media/jni/soundpool/android_media_SoundPool_SoundPoolImpl.cpp @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2008 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. + */ + +#include + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SoundPool-JNI" + +#include +#include +#include +#include +#include + +using namespace android; + +static struct fields_t { + jfieldID mNativeContext; + jmethodID mPostEvent; + jclass mSoundPoolClass; +} fields; + +static inline SoundPool* MusterSoundPool(JNIEnv *env, jobject thiz) { + return (SoundPool*)env->GetIntField(thiz, fields.mNativeContext); +} + +// ---------------------------------------------------------------------------- +static int +android_media_SoundPool_SoundPoolImpl_load_URL(JNIEnv *env, jobject thiz, jstring path, jint priority) +{ + ALOGV("android_media_SoundPool_SoundPoolImpl_load_URL"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (path == NULL) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return 0; + } + const char* s = env->GetStringUTFChars(path, NULL); + int id = ap->load(s, priority); + env->ReleaseStringUTFChars(path, s); + return id; +} + +static int +android_media_SoundPool_SoundPoolImpl_load_FD(JNIEnv *env, jobject thiz, jobject fileDescriptor, + jlong offset, jlong length, jint priority) +{ + ALOGV("android_media_SoundPool_SoundPoolImpl_load_FD"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return 0; + return ap->load(jniGetFDFromFileDescriptor(env, fileDescriptor), + int64_t(offset), int64_t(length), int(priority)); +} + +static bool +android_media_SoundPool_SoundPoolImpl_unload(JNIEnv *env, jobject thiz, jint sampleID) { + ALOGV("android_media_SoundPool_SoundPoolImpl_unload\n"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return 0; + return ap->unload(sampleID); +} + +static int +android_media_SoundPool_SoundPoolImpl_play(JNIEnv *env, jobject thiz, jint sampleID, + jfloat leftVolume, jfloat rightVolume, jint priority, jint loop, + jfloat rate) +{ + ALOGV("android_media_SoundPool_SoundPoolImpl_play\n"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return 0; + return ap->play(sampleID, leftVolume, rightVolume, priority, loop, rate); +} + +static void +android_media_SoundPool_SoundPoolImpl_pause(JNIEnv *env, jobject thiz, jint channelID) +{ + ALOGV("android_media_SoundPool_SoundPoolImpl_pause"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return; + ap->pause(channelID); +} + +static void +android_media_SoundPool_SoundPoolImpl_resume(JNIEnv *env, jobject thiz, jint channelID) +{ + ALOGV("android_media_SoundPool_SoundPoolImpl_resume"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return; + ap->resume(channelID); +} + +static void +android_media_SoundPool_SoundPoolImpl_autoPause(JNIEnv *env, jobject thiz) +{ + ALOGV("android_media_SoundPool_SoundPoolImpl_autoPause"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return; + ap->autoPause(); +} + +static void +android_media_SoundPool_SoundPoolImpl_autoResume(JNIEnv *env, jobject thiz) +{ + ALOGV("android_media_SoundPool_SoundPoolImpl_autoResume"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return; + ap->autoResume(); +} + +static void +android_media_SoundPool_SoundPoolImpl_stop(JNIEnv *env, jobject thiz, jint channelID) +{ + ALOGV("android_media_SoundPool_SoundPoolImpl_stop"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return; + ap->stop(channelID); +} + +static void +android_media_SoundPool_SoundPoolImpl_setVolume(JNIEnv *env, jobject thiz, jint channelID, + float leftVolume, float rightVolume) +{ + ALOGV("android_media_SoundPool_SoundPoolImpl_setVolume"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return; + ap->setVolume(channelID, leftVolume, rightVolume); +} + +static void +android_media_SoundPool_SoundPoolImpl_setPriority(JNIEnv *env, jobject thiz, jint channelID, + int priority) +{ + ALOGV("android_media_SoundPool_SoundPoolImpl_setPriority"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return; + ap->setPriority(channelID, priority); +} + +static void +android_media_SoundPool_SoundPoolImpl_setLoop(JNIEnv *env, jobject thiz, jint channelID, + int loop) +{ + ALOGV("android_media_SoundPool_SoundPoolImpl_setLoop"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return; + ap->setLoop(channelID, loop); +} + +static void +android_media_SoundPool_SoundPoolImpl_setRate(JNIEnv *env, jobject thiz, jint channelID, + float rate) +{ + ALOGV("android_media_SoundPool_SoundPoolImpl_setRate"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return; + ap->setRate(channelID, rate); +} + +static void android_media_callback(SoundPoolEvent event, SoundPool* soundPool, void* user) +{ + ALOGV("callback: (%d, %d, %d, %p, %p)", event.mMsg, event.mArg1, event.mArg2, soundPool, user); + JNIEnv *env = AndroidRuntime::getJNIEnv(); + env->CallStaticVoidMethod(fields.mSoundPoolClass, fields.mPostEvent, user, event.mMsg, event.mArg1, event.mArg2, NULL); +} + +static jint +android_media_SoundPool_SoundPoolImpl_native_setup(JNIEnv *env, jobject thiz, jobject weakRef, jint maxChannels, jint streamType, jint srcQuality) +{ + ALOGV("android_media_SoundPool_SoundPoolImpl_native_setup"); + SoundPool *ap = new SoundPool(maxChannels, (audio_stream_type_t) streamType, srcQuality); + if (ap == NULL) { + return -1; + } + + // save pointer to SoundPool C++ object in opaque field in Java object + env->SetIntField(thiz, fields.mNativeContext, (int)ap); + + // set callback with weak reference + jobject globalWeakRef = env->NewGlobalRef(weakRef); + ap->setCallback(android_media_callback, globalWeakRef); + return 0; +} + +static void +android_media_SoundPool_SoundPoolImpl_release(JNIEnv *env, jobject thiz) +{ + ALOGV("android_media_SoundPool_SoundPoolImpl_release"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap != NULL) { + + // release weak reference + jobject weakRef = (jobject) ap->getUserData(); + if (weakRef != NULL) { + env->DeleteGlobalRef(weakRef); + } + + // clear callback and native context + ap->setCallback(NULL, NULL); + env->SetIntField(thiz, fields.mNativeContext, 0); + delete ap; + } +} + +// ---------------------------------------------------------------------------- + +// Dalvik VM type signatures +static JNINativeMethod gMethods[] = { + { "_load", + "(Ljava/lang/String;I)I", + (void *)android_media_SoundPool_SoundPoolImpl_load_URL + }, + { "_load", + "(Ljava/io/FileDescriptor;JJI)I", + (void *)android_media_SoundPool_SoundPoolImpl_load_FD + }, + { "unload", + "(I)Z", + (void *)android_media_SoundPool_SoundPoolImpl_unload + }, + { "play", + "(IFFIIF)I", + (void *)android_media_SoundPool_SoundPoolImpl_play + }, + { "pause", + "(I)V", + (void *)android_media_SoundPool_SoundPoolImpl_pause + }, + { "resume", + "(I)V", + (void *)android_media_SoundPool_SoundPoolImpl_resume + }, + { "autoPause", + "()V", + (void *)android_media_SoundPool_SoundPoolImpl_autoPause + }, + { "autoResume", + "()V", + (void *)android_media_SoundPool_SoundPoolImpl_autoResume + }, + { "stop", + "(I)V", + (void *)android_media_SoundPool_SoundPoolImpl_stop + }, + { "setVolume", + "(IFF)V", + (void *)android_media_SoundPool_SoundPoolImpl_setVolume + }, + { "setPriority", + "(II)V", + (void *)android_media_SoundPool_SoundPoolImpl_setPriority + }, + { "setLoop", + "(II)V", + (void *)android_media_SoundPool_SoundPoolImpl_setLoop + }, + { "setRate", + "(IF)V", + (void *)android_media_SoundPool_SoundPoolImpl_setRate + }, + { "native_setup", + "(Ljava/lang/Object;III)I", + (void*)android_media_SoundPool_SoundPoolImpl_native_setup + }, + { "release", + "()V", + (void*)android_media_SoundPool_SoundPoolImpl_release + } +}; + +static const char* const kClassPathName = "android/media/SoundPool$SoundPoolImpl"; + +jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + JNIEnv* env = NULL; + jint result = -1; + jclass clazz; + + if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + ALOGE("ERROR: GetEnv failed\n"); + goto bail; + } + assert(env != NULL); + + clazz = env->FindClass(kClassPathName); + if (clazz == NULL) { + ALOGE("Can't find %s", kClassPathName); + goto bail; + } + + fields.mNativeContext = env->GetFieldID(clazz, "mNativeContext", "I"); + if (fields.mNativeContext == NULL) { + ALOGE("Can't find SoundPoolImpl.mNativeContext"); + goto bail; + } + + fields.mPostEvent = env->GetStaticMethodID(clazz, "postEventFromNative", + "(Ljava/lang/Object;IIILjava/lang/Object;)V"); + if (fields.mPostEvent == NULL) { + ALOGE("Can't find android/media/SoundPoolImpl.postEventFromNative"); + goto bail; + } + + // create a reference to class. Technically, we're leaking this reference + // since it's a static object. + fields.mSoundPoolClass = (jclass) env->NewGlobalRef(clazz); + + if (AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)) < 0) + goto bail; + + /* success -- return valid version number */ + result = JNI_VERSION_1_4; + +bail: + return result; +} -- cgit v1.1 From 3e72eb5245a439525976dbb9a67280b9b26b9f14 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 13 Jun 2013 15:25:25 -0700 Subject: Remove unused MediaPlayer methods Change-Id: Id63fdde7d0e4f096d3bb9eb4da5e0f37eb9dea21 --- media/jni/android_media_MediaPlayer.cpp | 44 --------------------------------- 1 file changed, 44 deletions(-) (limited to 'media/jni') diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 7c607ea..0f78649 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -525,14 +525,6 @@ android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, float leftVolume, process_media_player_call( env, thiz, mp->setVolume(leftVolume, rightVolume), NULL, NULL ); } -// FIXME: deprecated -static jobject -android_media_MediaPlayer_getFrameAt(JNIEnv *env, jobject thiz, jint msec) -{ - return NULL; -} - - // Sends the request and reply parcels to the media player via the // binder interface. static jint @@ -781,39 +773,6 @@ android_media_MediaPlayer_setRetransmitEndpoint(JNIEnv *env, jobject thiz, return ret; } -static jboolean -android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request) -{ - ALOGV("setParameter: key %d", key); - sp mp = getMediaPlayer(env, thiz); - if (mp == NULL ) { - jniThrowException(env, "java/lang/IllegalStateException", NULL); - return false; - } - - Parcel *request = parcelForJavaObject(env, java_request); - status_t err = mp->setParameter(key, *request); - if (err == OK) { - return true; - } else { - return false; - } -} - -static void -android_media_MediaPlayer_getParameter(JNIEnv *env, jobject thiz, jint key, jobject java_reply) -{ - ALOGV("getParameter: key %d", key); - sp mp = getMediaPlayer(env, thiz); - if (mp == NULL ) { - jniThrowException(env, "java/lang/IllegalStateException", NULL); - return; - } - - Parcel *reply = parcelForJavaObject(env, java_reply); - process_media_player_call(env, thiz, mp->getParameter(key, reply), NULL, NULL ); -} - static void android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject java_player) { @@ -912,7 +871,6 @@ static JNINativeMethod gMethods[] = { {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping}, {"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping}, {"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume}, - {"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt}, {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke}, {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter}, {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata}, @@ -924,8 +882,6 @@ static JNINativeMethod gMethods[] = { {"setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel}, {"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect}, {"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData}, - {"setParameter", "(ILandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_setParameter}, - {"getParameter", "(ILandroid/os/Parcel;)V", (void *)android_media_MediaPlayer_getParameter}, {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I", (void *)android_media_MediaPlayer_setRetransmitEndpoint}, {"setNextMediaPlayer", "(Landroid/media/MediaPlayer;)V", (void *)android_media_MediaPlayer_setNextMediaPlayer}, {"updateProxyConfig", "(Landroid/net/ProxyProperties;)V", (void *)android_media_MediaPlayer_updateProxyConfig}, -- cgit v1.1 From 212e78df9eb3bfff069de01aa7820cf4201c5f82 Mon Sep 17 00:00:00 2001 From: Zhijun He Date: Fri, 7 Jun 2013 11:36:23 -0700 Subject: ImageReader: Implementation of ImageReader and Image APIs Used for direct image data access from producer like camera or video decoder. Bug: 9254294 Change-Id: I1853af03f4487ac3585d86202f6140854471fa89 --- media/jni/Android.mk | 1 + media/jni/android_media_ImageReader.cpp | 747 ++++++++++++++++++++++++++++++++ media/jni/android_media_MediaPlayer.cpp | 6 + 3 files changed, 754 insertions(+) create mode 100644 media/jni/android_media_ImageReader.cpp (limited to 'media/jni') diff --git a/media/jni/Android.mk b/media/jni/Android.mk index 416a2a1..01b3174 100644 --- a/media/jni/Android.mk +++ b/media/jni/Android.mk @@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ + android_media_ImageReader.cpp \ android_media_MediaCrypto.cpp \ android_media_MediaCodec.cpp \ android_media_MediaCodecList.cpp \ diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp new file mode 100644 index 0000000..bdb07a6 --- /dev/null +++ b/media/jni/android_media_ImageReader.cpp @@ -0,0 +1,747 @@ +/* + * Copyright 2013 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_NDEBUG 0 +#define LOG_TAG "ImageReader_JNI" +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include +#include + +#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) ) + +#define ANDROID_MEDIA_IMAGEREADER_JNI_ID "mCpuConsumer" +#define ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID "mNativeContext" +#define ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID "mLockedBuffer" +#define ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID "mTimestamp" + +// ---------------------------------------------------------------------------- + +using namespace android; + +enum { + IMAGE_READER_MAX_NUM_PLANES = 3, +}; + +struct fields_t { + // For ImageReader class + jfieldID imageReaderContext; + jmethodID postEvent; + // For SurfaceImage class + jfieldID buffer; + jfieldID timeStamp; +}; + +struct classInfo_t { + jclass clazz; + jmethodID ctor; +}; + +static fields_t fields; +static classInfo_t surfPlaneClassInfo; + +// ---------------------------------------------------------------------------- + +class JNIImageReaderContext : public CpuConsumer::FrameAvailableListener +{ +public: + JNIImageReaderContext(JNIEnv* env, jobject weakThiz, jclass clazz, int maxImages); + + virtual ~JNIImageReaderContext(); + + virtual void onFrameAvailable(); + + CpuConsumer::LockedBuffer* getLockedBuffer(); + + void returnLockedBuffer(CpuConsumer::LockedBuffer* buffer); + + CpuConsumer* getCpuConsumer() { return mConsumer.get(); } + + void setCpuConsumer(sp consumer) { mConsumer = consumer; } + + void setBufferFormat(int format) { mFormat = format; } + int getBufferFormat() { return mFormat; } + + void setBufferWidth(int width) { mWidth = width; } + int getBufferWidth() { return mWidth; } + + void setBufferHeight(int height) { mHeight = height; } + int getBufferHeight() { return mHeight; } + +private: + static JNIEnv* getJNIEnv(bool* needsDetach); + static void detachJNI(); + + List mBuffers; + sp mConsumer; + jobject mWeakThiz; + jclass mClazz; + int mFormat; + int mWidth; + int mHeight; +}; + +JNIImageReaderContext::JNIImageReaderContext(JNIEnv* env, + jobject weakThiz, jclass clazz, int maxImages) : + mWeakThiz(env->NewGlobalRef(weakThiz)), + mClazz((jclass)env->NewGlobalRef(clazz)) { + for (int i = 0; i < maxImages; i++) { + CpuConsumer::LockedBuffer *buffer = new CpuConsumer::LockedBuffer; + mBuffers.push_back(buffer); + } +} + +JNIEnv* JNIImageReaderContext::getJNIEnv(bool* needsDetach) { + LOG_ALWAYS_FATAL_IF(needsDetach == NULL, "needsDetach is null!!!"); + *needsDetach = false; + JNIEnv* env = AndroidRuntime::getJNIEnv(); + if (env == NULL) { + JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL}; + JavaVM* vm = AndroidRuntime::getJavaVM(); + int result = vm->AttachCurrentThread(&env, (void*) &args); + if (result != JNI_OK) { + ALOGE("thread attach failed: %#x", result); + return NULL; + } + *needsDetach = true; + } + return env; +} + +void JNIImageReaderContext::detachJNI() { + JavaVM* vm = AndroidRuntime::getJavaVM(); + int result = vm->DetachCurrentThread(); + if (result != JNI_OK) { + ALOGE("thread detach failed: %#x", result); + } +} + +CpuConsumer::LockedBuffer* JNIImageReaderContext::getLockedBuffer() { + if (mBuffers.empty()) { + return NULL; + } + // Return a LockedBuffer pointer and remove it from the list + List::iterator it = mBuffers.begin(); + CpuConsumer::LockedBuffer* buffer = *it; + mBuffers.erase(it); + return buffer; +} + +void JNIImageReaderContext::returnLockedBuffer(CpuConsumer::LockedBuffer * buffer) { + mBuffers.push_back(buffer); +} + +JNIImageReaderContext::~JNIImageReaderContext() { + bool needsDetach = false; + JNIEnv* env = getJNIEnv(&needsDetach); + if (env != NULL) { + env->DeleteGlobalRef(mWeakThiz); + env->DeleteGlobalRef(mClazz); + } else { + ALOGW("leaking JNI object references"); + } + if (needsDetach) { + detachJNI(); + } + + // Delete LockedBuffers + for (List::iterator it = mBuffers.begin(); + it != mBuffers.end(); it++) { + delete *it; + } + mBuffers.clear(); + mConsumer.clear(); +} + +void JNIImageReaderContext::onFrameAvailable() +{ + ALOGV("%s: frame available", __FUNCTION__); + bool needsDetach = false; + JNIEnv* env = getJNIEnv(&needsDetach); + if (env != NULL) { + env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz); + } else { + ALOGW("onFrameAvailable event will not posted"); + } + if (needsDetach) { + detachJNI(); + } +} + +// ---------------------------------------------------------------------------- + +extern "C" { + +static JNIImageReaderContext* ImageReader_getContext(JNIEnv* env, jobject thiz) +{ + JNIImageReaderContext *ctx; + ctx = reinterpret_cast + (env->GetLongField(thiz, fields.imageReaderContext)); + return ctx; +} + +static CpuConsumer* ImageReader_getCpuConsumer(JNIEnv* env, jobject thiz) +{ + ALOGV("%s:", __FUNCTION__); + JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz); + if (ctx == NULL) { + jniThrowRuntimeException(env, "ImageReaderContext is not initialized"); + return NULL; + } + return ctx->getCpuConsumer(); +} + +static void ImageReader_setNativeContext(JNIEnv* env, + jobject thiz, sp ctx) +{ + ALOGV("%s:", __FUNCTION__); + JNIImageReaderContext* const p = ImageReader_getContext(env, thiz); + if (ctx != 0) { + ctx->incStrong((void*)ImageReader_setNativeContext); + } + if (p) { + p->decStrong((void*)ImageReader_setNativeContext); + } + env->SetLongField(thiz, fields.imageReaderContext, reinterpret_cast(ctx.get())); +} + +static CpuConsumer::LockedBuffer* Image_getLockedBuffer(JNIEnv* env, jobject image) +{ + return reinterpret_cast(env->GetLongField(image, fields.buffer)); +} + +static void Image_setBuffer(JNIEnv* env, jobject thiz, + const CpuConsumer::LockedBuffer* buffer) +{ + env->SetLongField(thiz, fields.buffer, reinterpret_cast(buffer)); +} + +// Some formats like JPEG defined with different values between android.graphics.ImageFormat and +// graphics.h, need convert to the one defined in graphics.h here. +static int Image_getPixelFormat(JNIEnv* env, int format) +{ + int jpegFormat, rawSensorFormat; + jfieldID fid; + + ALOGV("%s: format = 0x%x", __FUNCTION__, format); + + jclass imageFormatClazz = env->FindClass("android/graphics/ImageFormat"); + ALOG_ASSERT(imageFormatClazz != NULL); + + fid = env->GetStaticFieldID(imageFormatClazz, "JPEG", "I"); + jpegFormat = env->GetStaticIntField(imageFormatClazz, fid); + fid = env->GetStaticFieldID(imageFormatClazz, "RAW_SENSOR", "I"); + rawSensorFormat = env->GetStaticIntField(imageFormatClazz, fid); + + // Translate the JPEG to BLOB for camera purpose, an add more if more mismatch is found. + if (format == jpegFormat) { + format = HAL_PIXEL_FORMAT_BLOB; + } + // Same thing for RAW_SENSOR format + if (format == rawSensorFormat) { + format = HAL_PIXEL_FORMAT_RAW_SENSOR; + } + + return format; +} + +static void Image_getLockedBufferInfo(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx, + uint8_t **base, uint32_t *size) +{ + ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!"); + ALOG_ASSERT(base != NULL, "base is NULL!!!"); + ALOG_ASSERT(size != NULL, "size is NULL!!!"); + ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0)); + + ALOGV("%s: buffer: 0x%p", __FUNCTION__, buffer); + + uint32_t dataSize, ySize, cSize, cStride; + uint8_t *cb, *cr; + uint8_t *pData = NULL; + + dataSize = ySize = cSize = cStride = 0; + int32_t fmt = buffer->format; + switch (fmt) { + case HAL_PIXEL_FORMAT_YCbCr_420_888: + pData = + (idx == 0) ? + buffer->data : + (idx == 1) ? + buffer->dataCb : + buffer->dataCr; + if (idx == 0) { + dataSize = buffer->stride * buffer->height; + } else { + dataSize = buffer->chromaStride * buffer->height / 2; + } + break; + // NV21 + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + cr = buffer->data + (buffer->stride * buffer->height); + cb = cr + 1; + ySize = buffer->width * buffer->height; + cSize = buffer->width * buffer->height / 2; + + pData = + (idx == 0) ? + buffer->data : + (idx == 1) ? + cb: + cr; + + dataSize = (idx == 0) ? ySize : cSize; + break; + case HAL_PIXEL_FORMAT_YV12: + // Y and C stride need to be 16 pixel aligned. + LOG_ALWAYS_FATAL_IF(buffer->stride % 16, + "Stride is not 16 pixel aligned %d", buffer->stride); + + ySize = buffer->stride * buffer->height; + cStride = ALIGN(buffer->stride / 2, 16); + cr = buffer->data + ySize; + cSize = cStride * buffer->height / 2; + cb = cr + cSize; + + pData = + (idx == 0) ? + buffer->data : + (idx == 1) ? + cb : + cr; + dataSize = (idx == 0) ? ySize : cSize; + break; + case HAL_PIXEL_FORMAT_Y8: + // Single plane, 8bpp. + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + + pData = buffer->data; + dataSize = buffer->stride * buffer->height; + break; + case HAL_PIXEL_FORMAT_Y16: + // Single plane, 16bpp, strides are specified in pixels, not in bytes + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + + pData = buffer->data; + dataSize = buffer->stride * buffer->height * 2; + break; + case HAL_PIXEL_FORMAT_BLOB: + // Used for JPEG data, height must be 1, width == size, single plane. + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + ALOG_ASSERT(buffer->height == 1, "JPEG should has height value %d", buffer->height); + + pData = buffer->data; + dataSize = buffer->width; + break; + case HAL_PIXEL_FORMAT_RAW_SENSOR: + // Single plane 16bpp bayer data. + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + pData = buffer->data; + dataSize = buffer->width * 2 * buffer->height; + break; + default: + jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException", + "Pixel format: 0x%x is unsupported", fmt); + break; + } + + *base = pData; + *size = dataSize; +} + +static jint Image_imageGetPixelStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx) +{ + ALOGV("%s: buffer index: %d", __FUNCTION__, idx); + ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0), "Index is out of range:%d", idx); + + int pixelStride = 0; + ALOG_ASSERT(buffer != NULL, "buffer is NULL"); + + int32_t fmt = buffer->format; + switch (fmt) { + case HAL_PIXEL_FORMAT_YCbCr_420_888: + pixelStride = (idx == 0) ? 1 : buffer->chromaStep; + break; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + pixelStride = (idx == 0) ? 1 : 2; + break; + case HAL_PIXEL_FORMAT_Y8: + // Single plane 8bpp data. + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + pixelStride; + break; + case HAL_PIXEL_FORMAT_YV12: + pixelStride = 1; + break; + case HAL_PIXEL_FORMAT_BLOB: + // Used for JPEG data, single plane, row and pixel strides are 0 + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + pixelStride = 0; + break; + case HAL_PIXEL_FORMAT_Y16: + case HAL_PIXEL_FORMAT_RAW_SENSOR: + // Single plane 16bpp data. + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + pixelStride = 2; + break; + default: + jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException", + "Pixel format: 0x%x is unsupported", fmt); + break; + } + + return pixelStride; +} + +static jint Image_imageGetRowStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx) +{ + ALOGV("%s: buffer index: %d", __FUNCTION__, idx); + ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0)); + + int rowStride = 0; + ALOG_ASSERT(buffer != NULL, "buffer is NULL"); + + int32_t fmt = buffer->format; + + switch (fmt) { + case HAL_PIXEL_FORMAT_YCbCr_420_888: + rowStride = (idx == 0) ? buffer->stride : buffer->chromaStride; + break; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + rowStride = buffer->width; + break; + case HAL_PIXEL_FORMAT_YV12: + LOG_ALWAYS_FATAL_IF(buffer->stride % 16, + "Stride is not 16 pixel aligned %d", buffer->stride); + rowStride = (idx == 0) ? buffer->stride : ALIGN(buffer->stride / 2, 16); + break; + case HAL_PIXEL_FORMAT_BLOB: + // Used for JPEG data, single plane, row and pixel strides are 0 + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + rowStride = 0; + break; + case HAL_PIXEL_FORMAT_Y8: + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + LOG_ALWAYS_FATAL_IF(buffer->stride % 16, + "Stride is not 16 pixel aligned %d", buffer->stride); + rowStride = buffer->stride; + break; + case HAL_PIXEL_FORMAT_Y16: + case HAL_PIXEL_FORMAT_RAW_SENSOR: + // In native side, strides are specified in pixels, not in bytes. + // Single plane 16bpp bayer data. even width/height, + // row stride multiple of 16 pixels (32 bytes) + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + LOG_ALWAYS_FATAL_IF(buffer->stride % 16, + "Stride is not 16 pixel aligned %d", buffer->stride); + rowStride = buffer->stride * 2; + break; + default: + ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt); + jniThrowException(env, "java/lang/UnsupportedOperationException", + "unsupported buffer format"); + break; + } + + return rowStride; +} + +// ---------------------------------------------------------------------------- + +static void ImageReader_classInit(JNIEnv* env, jclass clazz) +{ + ALOGV("%s:", __FUNCTION__); + + jclass imageClazz = env->FindClass("android/media/ImageReader$SurfaceImage"); + LOG_ALWAYS_FATAL_IF(imageClazz == NULL, + "can't find android/graphics/ImageReader$SurfaceImage"); + fields.buffer = env->GetFieldID(imageClazz, ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID, "J"); + LOG_ALWAYS_FATAL_IF(fields.buffer == NULL, + "can't find android/graphics/ImageReader.%s", + ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID); + + fields.timeStamp = env->GetFieldID(imageClazz, ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID, "J"); + LOG_ALWAYS_FATAL_IF(fields.timeStamp == NULL, + "can't find android/graphics/ImageReader.%s", + ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID); + + fields.imageReaderContext = env->GetFieldID(clazz, ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID, "J"); + LOG_ALWAYS_FATAL_IF(fields.imageReaderContext == NULL, + "can't find android/graphics/ImageReader.%s", + ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID); + + fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative", + "(Ljava/lang/Object;)V"); + LOG_ALWAYS_FATAL_IF(fields.postEvent == NULL, + "can't find android/graphics/ImageReader.postEventFromNative"); + + jclass planeClazz = env->FindClass("android/media/ImageReader$SurfaceImage$SurfacePlane"); + LOG_ALWAYS_FATAL_IF(planeClazz == NULL, "Can not find SurfacePlane class"); + // FindClass only gives a local reference of jclass object. + surfPlaneClassInfo.clazz = (jclass) env->NewGlobalRef(planeClazz); + surfPlaneClassInfo.ctor = env->GetMethodID(surfPlaneClassInfo.clazz, "", + "(Landroid/media/ImageReader$SurfaceImage;III)V"); + LOG_ALWAYS_FATAL_IF(surfPlaneClassInfo.ctor == NULL, "Can not find SurfacePlane constructor"); +} + +static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, + jint width, jint height, jint format, jint maxImages) +{ + status_t res; + int nativeFormat; + + ALOGV("%s: width:%d, height: %d, format: 0x%x, maxImages:%d", + __FUNCTION__, width, height, format, maxImages); + + nativeFormat = Image_getPixelFormat(env, format); + + sp consumer = new CpuConsumer(maxImages); + // TODO: throw dvm exOutOfMemoryError? + if (consumer == NULL) { + jniThrowRuntimeException(env, "Failed to allocate native CpuConsumer"); + return; + } + + jclass clazz = env->GetObjectClass(thiz); + if (clazz == NULL) { + jniThrowRuntimeException(env, "Can't find android/graphics/ImageReader"); + return; + } + sp ctx(new JNIImageReaderContext(env, weakThiz, clazz, maxImages)); + ctx->setCpuConsumer(consumer); + consumer->setFrameAvailableListener(ctx); + ImageReader_setNativeContext(env, thiz, ctx); + ctx->setBufferFormat(nativeFormat); + ctx->setBufferWidth(width); + ctx->setBufferHeight(height); + + // Set the width/height/format to the CpuConsumer + res = consumer->setDefaultBufferSize(width, height); + if (res != OK) { + jniThrowException(env, "java/lang/IllegalStateException", + "Failed to set CpuConsumer buffer size"); + return; + } + res = consumer->setDefaultBufferFormat(nativeFormat); + if (res != OK) { + jniThrowException(env, "java/lang/IllegalStateException", + "Failed to set CpuConsumer buffer format"); + } +} + +static void ImageReader_close(JNIEnv* env, jobject thiz) +{ + ALOGV("%s:", __FUNCTION__); + + JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz); + if (ctx == NULL) { + // ImageReader is already closed. + return; + } + + CpuConsumer* consumer = ImageReader_getCpuConsumer(env, thiz); + if (consumer != NULL) { + consumer->abandon(); + consumer->setFrameAvailableListener(NULL); + } + ImageReader_setNativeContext(env, thiz, NULL); +} + +static void ImageReader_imageRelease(JNIEnv* env, jobject thiz, jobject image) +{ + ALOGV("%s:", __FUNCTION__); + JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz); + if (ctx == NULL) { + ALOGW("ImageReader#close called before Image#close, consider calling Image#close first"); + return; + } + + CpuConsumer* consumer = ctx->getCpuConsumer(); + CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, image); + if (!buffer) { + ALOGW("Image already released!!!"); + return; + } + consumer->unlockBuffer(*buffer); + Image_setBuffer(env, image, NULL); + ctx->returnLockedBuffer(buffer); +} + +static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, + jobject image) +{ + ALOGV("%s:", __FUNCTION__); + JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz); + if (ctx == NULL) { + jniThrowRuntimeException(env, "ImageReaderContext is not initialized"); + return false; + } + + CpuConsumer* consumer = ctx->getCpuConsumer(); + CpuConsumer::LockedBuffer* buffer = ctx->getLockedBuffer(); + if (buffer == NULL) { + ALOGE("Unable to acquire a lockedBuffer, very likely client tries to lock more than" + "maxImages buffers"); + return false; + } + status_t res = consumer->lockNextBuffer(buffer); + if (res != NO_ERROR) { + ALOGE("%s Fail to lockNextBuffer with error: 0x%x ", __FUNCTION__, res); + return false; + } + + + // Check if the left-top corner of the crop rect is origin, we currently assume this point is + // zero, will revist this once this assumption turns out problematic. + Point lt = buffer->crop.leftTop(); + if (lt.x != 0 || lt.y != 0) { + ALOGE("crop left: %d, top = %d", lt.x, lt.y); + jniThrowException(env, "java/lang/UnsupportedOperationException", + "crop left top corner need to at origin"); + } + + // Check if the producer buffer configurations match what ImageReader configured. + // We want to fail for the very first image because this case is too bad. + int outputWidth = buffer->crop.getWidth() + 1; + int outputHeight = buffer->crop.getHeight() + 1; + int imageReaderWidth = ctx->getBufferWidth(); + int imageReaderHeight = ctx->getBufferHeight(); + if ((imageReaderWidth != outputWidth) || + (imageReaderHeight != outputHeight)) { + // Spew warning for now, since MediaCodec decoder has a bug to setup the right crop + // TODO: make it throw exception once the decoder bug is fixed. + ALOGW("Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d", + outputWidth, outputHeight, imageReaderWidth, imageReaderHeight); + } + + if (ctx->getBufferFormat() != buffer->format) { + // Return the buffer to the queue. + consumer->unlockBuffer(*buffer); + ctx->returnLockedBuffer(buffer); + + // Throw exception + ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x", + buffer->format, ctx->getBufferFormat()); + jniThrowException(env, "java/lang/UnsupportedOperationException", + "The producer output buffer configuration doesn't match the ImageReader" + "configured"); + return false; + } + // Set SurfaceImage instance member variables + Image_setBuffer(env, image, buffer); + env->SetLongField(image, fields.timeStamp, static_cast(buffer->timestamp)); + + return true; +} + +static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz) +{ + ALOGV("%s: ", __FUNCTION__); + + CpuConsumer* consumer = ImageReader_getCpuConsumer(env, thiz); + if (consumer == NULL) { + jniThrowRuntimeException(env, "CpuConsumer is uninitialized"); + return NULL; + } + + // Wrap the IGBP in a Java-language Surface. + return android_view_Surface_createFromIGraphicBufferProducer(env, + consumer->getProducerInterface()); +} + +static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx) +{ + int rowStride, pixelStride; + ALOGV("%s: buffer index: %d", __FUNCTION__, idx); + + CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz); + + ALOG_ASSERT(buffer != NULL); + if (buffer == NULL) { + jniThrowException(env, "java/lang/IllegalStateException", "Image was released"); + } + rowStride = Image_imageGetRowStride(env, buffer, idx); + pixelStride = Image_imageGetPixelStride(env, buffer, idx); + + jobject surfPlaneObj = env->NewObject(surfPlaneClassInfo.clazz, surfPlaneClassInfo.ctor, + thiz, idx, rowStride, pixelStride); + + return surfPlaneObj; +} + +static jobject Image_getByteBuffer(JNIEnv* env, jobject thiz, int idx) +{ + uint8_t *base = NULL; + uint32_t size = 0; + jobject byteBuffer; + + ALOGV("%s: buffer index: %d", __FUNCTION__, idx); + + CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz); + + if (buffer == NULL) { + jniThrowException(env, "java/lang/IllegalStateException", "Image was released"); + } + + // Create byteBuffer from native buffer + Image_getLockedBufferInfo(env, buffer, idx, &base, &size); + byteBuffer = env->NewDirectByteBuffer(base, size); + // TODO: throw dvm exOutOfMemoryError? + if ((byteBuffer == NULL) && (env->ExceptionCheck() == false)) { + jniThrowException(env, "java/lang/IllegalStateException", "Failed to allocate ByteBuffer"); + } + + return byteBuffer; +} + +} // extern "C" + +// ---------------------------------------------------------------------------- + +static JNINativeMethod gImageReaderMethods[] = { + {"nativeClassInit", "()V", (void*)ImageReader_classInit }, + {"nativeInit", "(Ljava/lang/Object;IIII)V", (void*)ImageReader_init }, + {"nativeClose", "()V", (void*)ImageReader_close }, + {"nativeReleaseImage", "(Landroid/media/Image;)V", (void*)ImageReader_imageRelease }, + {"nativeImageSetup", "(Landroid/media/Image;)Z", (void*)ImageReader_imageSetup }, + {"nativeGetSurface", "()Landroid/view/Surface;", (void*)ImageReader_getSurface }, +}; + +static JNINativeMethod gImageMethods[] = { + {"nativeImageGetBuffer", "(I)Ljava/nio/ByteBuffer;", (void*)Image_getByteBuffer }, + {"nativeCreatePlane", "(I)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;", + (void*)Image_createSurfacePlane }, +}; + +int register_android_media_ImageReader(JNIEnv *env) { + + int ret1 = AndroidRuntime::registerNativeMethods(env, + "android/media/ImageReader", gImageReaderMethods, NELEM(gImageReaderMethods)); + + int ret2 = AndroidRuntime::registerNativeMethods(env, + "android/media/ImageReader$SurfaceImage", gImageMethods, NELEM(gImageMethods)); + + return (ret1 || ret2); +} diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 0f78649..9b66c06 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -896,6 +896,7 @@ static int register_android_media_MediaPlayer(JNIEnv *env) "android/media/MediaPlayer", gMethods, NELEM(gMethods)); } +extern int register_android_media_ImageReader(JNIEnv *env); extern int register_android_media_Crypto(JNIEnv *env); extern int register_android_media_Drm(JNIEnv *env); extern int register_android_media_MediaCodec(JNIEnv *env); @@ -923,6 +924,11 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) } assert(env != NULL); + if (register_android_media_ImageReader(env) < 0) { + ALOGE("ERROR: ImageReader native registration failed"); + goto bail; + } + if (register_android_media_MediaPlayer(env) < 0) { ALOGE("ERROR: MediaPlayer native registration failed\n"); goto bail; -- cgit v1.1 From 534046d2b12fd13776ad782b982649cb0bea9b79 Mon Sep 17 00:00:00 2001 From: Zhijun He Date: Mon, 1 Jul 2013 11:03:41 -0700 Subject: ImageReader: get correct jpeg size. the jpeg size was set to the buffer width, which is the max jpeg buffer size. the right size can be obtained by parsing the camera3_jpeg_blob data sent by hal. Also correct the buffer size check when crop is not set. Bug: 9254294 Change-Id: Ic73de47ef97efa4eb356a399c1576715e2eacbfd --- media/jni/Android.mk | 2 ++ media/jni/android_media_ImageReader.cpp | 39 ++++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) (limited to 'media/jni') diff --git a/media/jni/Android.mk b/media/jni/Android.mk index 01b3174..63a61e2 100644 --- a/media/jni/Android.mk +++ b/media/jni/Android.mk @@ -57,6 +57,8 @@ LOCAL_C_INCLUDES += \ frameworks/av/media/libstagefright/codecs/amrnb/common/include \ frameworks/av/media/mtp \ frameworks/native/include/media/openmax \ + $(call include-path-for, libhardware)/hardware \ + system/media/camera/include \ $(PV_INCLUDES) \ $(JNI_H_INCLUDE) \ $(call include-path-for, corecg graphics) diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index bdb07a6..7866df4 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -268,6 +269,29 @@ static int Image_getPixelFormat(JNIEnv* env, int format) return format; } +static uint32_t Image_getJpegSize(CpuConsumer::LockedBuffer* buffer) +{ + ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!"); + uint32_t size = 0; + uint32_t width = buffer->width; + uint8_t* jpegBuffer = buffer->data; + + // First check for JPEG transport header at the end of the buffer + uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob)); + struct camera3_jpeg_blob *blob = (struct camera3_jpeg_blob*)(header); + if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) { + size = blob->jpeg_size; + ALOGV("%s: Jpeg size = %d", __FUNCTION__, size); + } + + // failed to find size, default to whole buffer + if (size == 0) { + size = width; + } + + return size; +} + static void Image_getLockedBufferInfo(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx, uint8_t **base, uint32_t *size) { @@ -353,7 +377,7 @@ static void Image_getLockedBufferInfo(JNIEnv* env, CpuConsumer::LockedBuffer* bu ALOG_ASSERT(buffer->height == 1, "JPEG should has height value %d", buffer->height); pData = buffer->data; - dataSize = buffer->width; + dataSize = Image_getJpegSize(buffer); break; case HAL_PIXEL_FORMAT_RAW_SENSOR: // Single plane 16bpp bayer data. @@ -624,8 +648,17 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, // Check if the producer buffer configurations match what ImageReader configured. // We want to fail for the very first image because this case is too bad. - int outputWidth = buffer->crop.getWidth() + 1; - int outputHeight = buffer->crop.getHeight() + 1; + int outputWidth = buffer->width; + int outputHeight = buffer->height; + + // Correct with/height when crop is set. + if (buffer->crop.getWidth() > 0) { + outputWidth = buffer->crop.getWidth() + 1; + } + if (buffer->crop.getHeight() > 0) { + outputHeight = buffer->crop.getHeight() + 1; + } + int imageReaderWidth = ctx->getBufferWidth(); int imageReaderHeight = ctx->getBufferHeight(); if ((imageReaderWidth != outputWidth) || -- cgit v1.1 From b550929b7a4b0d5f9645a7a1ebf287d3f13cf1af Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 12 Jul 2013 22:06:31 -0700 Subject: always pass the BufferQueue explicitely to consumers Change-Id: I32e380979a3f4c6b1dfb440cc5b5c3d30d7607db --- media/jni/android_media_ImageReader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'media/jni') diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 7866df4..5856057 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -541,7 +541,8 @@ static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, nativeFormat = Image_getPixelFormat(env, format); - sp consumer = new CpuConsumer(maxImages); + sp bq = new BufferQueue(); + sp consumer = new CpuConsumer(bq, maxImages); // TODO: throw dvm exOutOfMemoryError? if (consumer == NULL) { jniThrowRuntimeException(env, "Failed to allocate native CpuConsumer"); -- cgit v1.1 From e32632682ca9207bd247ca27012cf670b5c23f54 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 16 Jul 2013 22:54:56 -0700 Subject: update to new Consumer APIs Change-Id: I8649f3add40e0aeeeb0396b98e2cb93312e8e990 --- media/jni/android_media_ImageReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media/jni') diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 5856057..d876bd2 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -542,7 +542,7 @@ static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, nativeFormat = Image_getPixelFormat(env, format); sp bq = new BufferQueue(); - sp consumer = new CpuConsumer(bq, maxImages); + sp consumer = new CpuConsumer(bq, true, maxImages); // TODO: throw dvm exOutOfMemoryError? if (consumer == NULL) { jniThrowRuntimeException(env, "Failed to allocate native CpuConsumer"); -- cgit v1.1 From 7f4d3147d1851d2f0c544e45390c139bda9fd9aa Mon Sep 17 00:00:00 2001 From: Zhijun He Date: Tue, 23 Jul 2013 07:54:38 -0700 Subject: camera2: Implement CameraDevice#waitUntilIdle Also cleanup some logging/comments. Change-Id: Id1a4dd853519802a2b74b8d2172095ba388329e6 --- media/jni/android_media_ImageReader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'media/jni') diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index d876bd2..c1c965a 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -300,7 +300,7 @@ static void Image_getLockedBufferInfo(JNIEnv* env, CpuConsumer::LockedBuffer* bu ALOG_ASSERT(size != NULL, "size is NULL!!!"); ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0)); - ALOGV("%s: buffer: 0x%p", __FUNCTION__, buffer); + ALOGV("%s: buffer: %p", __FUNCTION__, buffer); uint32_t dataSize, ySize, cSize, cStride; uint8_t *cb, *cr; @@ -633,7 +633,7 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, } status_t res = consumer->lockNextBuffer(buffer); if (res != NO_ERROR) { - ALOGE("%s Fail to lockNextBuffer with error: 0x%x ", __FUNCTION__, res); + ALOGE("%s Fail to lockNextBuffer with error: %d ", __FUNCTION__, res); return false; } -- cgit v1.1 From 3ed38266c1647c6219ae5ad89cb3f867cf66caaa Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Fri, 2 Aug 2013 23:24:51 -0700 Subject: Define error codes for MediaCodec.CryptoException Define specific failure cases so apps have the information they need to deal with these conditions. Also adds a new ResourceBusyException to MediaDrm Change-Id: Iaecf269d58108f28179974b05671bf29b9fe4b7d related-to-bug: 10157154 related-to-bug: 9695816 --- media/jni/android_media_MediaCodec.cpp | 47 +++++++++++++++++++++++++++++++--- media/jni/android_media_MediaDrm.cpp | 3 +++ 2 files changed, 47 insertions(+), 3 deletions(-) (limited to 'media/jni') diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index cd1d9ce..8689e19 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -49,9 +49,14 @@ enum { DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3, }; +struct CryptoErrorCodes { + jint cryptoErrorNoKey; + jint cryptoErrorKeyExpired; + jint cryptoErrorResourceBusy; +} gCryptoErrorCodes; + struct fields_t { jfieldID context; - jfieldID cryptoInfoNumSubSamplesID; jfieldID cryptoInfoNumBytesOfClearDataID; jfieldID cryptoInfoNumBytesOfEncryptedDataID; @@ -342,6 +347,21 @@ static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) { jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error"); + /* translate OS errors to Java API CryptoException errorCodes */ + switch (err) { + case ERROR_DRM_NO_LICENSE: + err = gCryptoErrorCodes.cryptoErrorNoKey; + break; + case ERROR_DRM_LICENSE_EXPIRED: + err = gCryptoErrorCodes.cryptoErrorKeyExpired; + break; + case ERROR_DRM_RESOURCE_BUSY: + err = gCryptoErrorCodes.cryptoErrorResourceBusy; + break; + default: + break; + } + jthrowable exception = (jthrowable)env->NewObject(clazz, constructID, err, msgObj); @@ -350,9 +370,8 @@ static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) { static jint throwExceptionAsNecessary( JNIEnv *env, status_t err, const char *msg = NULL) { - if (err >= ERROR_DRM_WV_VENDOR_MIN && err <= ERROR_DRM_WV_VENDOR_MAX) { + if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) { // We'll throw our custom MediaCodec.CryptoException - throwCryptoException(env, err, msg); return 0; } @@ -370,6 +389,12 @@ static jint throwExceptionAsNecessary( case INFO_OUTPUT_BUFFERS_CHANGED: return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED; + case ERROR_DRM_NO_LICENSE: + case ERROR_DRM_LICENSE_EXPIRED: + case ERROR_DRM_RESOURCE_BUSY: + throwCryptoException(env, err, msg); + break; + default: { jniThrowException(env, "java/lang/IllegalStateException", msg); @@ -852,6 +877,22 @@ static void android_media_MediaCodec_native_init(JNIEnv *env) { gFields.cryptoInfoModeID = env->GetFieldID(clazz, "mode", "I"); CHECK(gFields.cryptoInfoModeID != NULL); + + clazz = env->FindClass("android/media/MediaCodec$CryptoException"); + CHECK(clazz != NULL); + + jfieldID field; + field = env->GetStaticFieldID(clazz, "ERROR_NO_KEY", "I"); + CHECK(field != NULL); + gCryptoErrorCodes.cryptoErrorNoKey = env->GetStaticIntField(clazz, field); + + field = env->GetStaticFieldID(clazz, "ERROR_KEY_EXPIRED", "I"); + CHECK(field != NULL); + gCryptoErrorCodes.cryptoErrorKeyExpired = env->GetStaticIntField(clazz, field); + + field = env->GetStaticFieldID(clazz, "ERROR_RESOURCE_BUSY", "I"); + CHECK(field != NULL); + gCryptoErrorCodes.cryptoErrorResourceBusy = env->GetStaticIntField(clazz, field); } static void android_media_MediaCodec_native_setup( diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index 7799ca4..16a1e48 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -242,6 +242,9 @@ static bool throwExceptionAsNecessary( } else if (err == ERROR_DRM_NOT_PROVISIONED) { jniThrowException(env, "android/media/NotProvisionedException", msg); return true; + } else if (err == ERROR_DRM_RESOURCE_BUSY) { + jniThrowException(env, "android/media/ResourceBusyException", msg); + return true; } else if (err == ERROR_DRM_DEVICE_REVOKED) { jniThrowException(env, "android/media/DeniedByServerException", msg); return true; -- cgit v1.1 From ef961215599b1c154130d4e64e46a401d6bfef67 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Mon, 5 Aug 2013 20:39:29 -0700 Subject: Minor style cleanups. A few changes to demonstrate a slightly cleaner way to write JNI code in the framework especially when multiple types are involved. We use this pattern in many other places outside of the media stack. Added more detail to the UnsupportedOperationException that occurs when buffer formats don't match. Change-Id: Ic894dc1bd71b387f1be6ea1798fa59e533e9574f --- media/jni/android_media_ImageReader.cpp | 89 ++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 40 deletions(-) (limited to 'media/jni') diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index c1c965a..b9ed022 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -47,22 +48,20 @@ enum { IMAGE_READER_MAX_NUM_PLANES = 3, }; -struct fields_t { - // For ImageReader class - jfieldID imageReaderContext; - jmethodID postEvent; - // For SurfaceImage class - jfieldID buffer; - jfieldID timeStamp; -}; +static struct { + jfieldID mNativeContext; + jmethodID postEventFromNative; +} gImageReaderClassInfo; + +static struct { + jfieldID mLockedBuffer; + jfieldID mTimestamp; +} gSurfaceImageClassInfo; -struct classInfo_t { +static struct { jclass clazz; jmethodID ctor; -}; - -static fields_t fields; -static classInfo_t surfPlaneClassInfo; +} gSurfacePlaneClassInfo; // ---------------------------------------------------------------------------- @@ -183,7 +182,7 @@ void JNIImageReaderContext::onFrameAvailable() bool needsDetach = false; JNIEnv* env = getJNIEnv(&needsDetach); if (env != NULL) { - env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz); + env->CallStaticVoidMethod(mClazz, gImageReaderClassInfo.postEventFromNative, mWeakThiz); } else { ALOGW("onFrameAvailable event will not posted"); } @@ -200,7 +199,7 @@ static JNIImageReaderContext* ImageReader_getContext(JNIEnv* env, jobject thiz) { JNIImageReaderContext *ctx; ctx = reinterpret_cast - (env->GetLongField(thiz, fields.imageReaderContext)); + (env->GetLongField(thiz, gImageReaderClassInfo.mNativeContext)); return ctx; } @@ -226,18 +225,20 @@ static void ImageReader_setNativeContext(JNIEnv* env, if (p) { p->decStrong((void*)ImageReader_setNativeContext); } - env->SetLongField(thiz, fields.imageReaderContext, reinterpret_cast(ctx.get())); + env->SetLongField(thiz, gImageReaderClassInfo.mNativeContext, + reinterpret_cast(ctx.get())); } static CpuConsumer::LockedBuffer* Image_getLockedBuffer(JNIEnv* env, jobject image) { - return reinterpret_cast(env->GetLongField(image, fields.buffer)); + return reinterpret_cast( + env->GetLongField(image, gSurfaceImageClassInfo.mLockedBuffer)); } static void Image_setBuffer(JNIEnv* env, jobject thiz, const CpuConsumer::LockedBuffer* buffer) { - env->SetLongField(thiz, fields.buffer, reinterpret_cast(buffer)); + env->SetLongField(thiz, gSurfaceImageClassInfo.mLockedBuffer, reinterpret_cast(buffer)); } // Some formats like JPEG defined with different values between android.graphics.ImageFormat and @@ -501,33 +502,37 @@ static void ImageReader_classInit(JNIEnv* env, jclass clazz) jclass imageClazz = env->FindClass("android/media/ImageReader$SurfaceImage"); LOG_ALWAYS_FATAL_IF(imageClazz == NULL, "can't find android/graphics/ImageReader$SurfaceImage"); - fields.buffer = env->GetFieldID(imageClazz, ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID, "J"); - LOG_ALWAYS_FATAL_IF(fields.buffer == NULL, + gSurfaceImageClassInfo.mLockedBuffer = env->GetFieldID( + imageClazz, ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID, "J"); + LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mLockedBuffer == NULL, "can't find android/graphics/ImageReader.%s", ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID); - fields.timeStamp = env->GetFieldID(imageClazz, ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID, "J"); - LOG_ALWAYS_FATAL_IF(fields.timeStamp == NULL, + gSurfaceImageClassInfo.mTimestamp = env->GetFieldID( + imageClazz, ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID, "J"); + LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mTimestamp == NULL, "can't find android/graphics/ImageReader.%s", ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID); - fields.imageReaderContext = env->GetFieldID(clazz, ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID, "J"); - LOG_ALWAYS_FATAL_IF(fields.imageReaderContext == NULL, + gImageReaderClassInfo.mNativeContext = env->GetFieldID( + clazz, ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID, "J"); + LOG_ALWAYS_FATAL_IF(gImageReaderClassInfo.mNativeContext == NULL, "can't find android/graphics/ImageReader.%s", ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID); - fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative", - "(Ljava/lang/Object;)V"); - LOG_ALWAYS_FATAL_IF(fields.postEvent == NULL, + gImageReaderClassInfo.postEventFromNative = env->GetStaticMethodID( + clazz, "postEventFromNative", "(Ljava/lang/Object;)V"); + LOG_ALWAYS_FATAL_IF(gImageReaderClassInfo.postEventFromNative == NULL, "can't find android/graphics/ImageReader.postEventFromNative"); jclass planeClazz = env->FindClass("android/media/ImageReader$SurfaceImage$SurfacePlane"); LOG_ALWAYS_FATAL_IF(planeClazz == NULL, "Can not find SurfacePlane class"); // FindClass only gives a local reference of jclass object. - surfPlaneClassInfo.clazz = (jclass) env->NewGlobalRef(planeClazz); - surfPlaneClassInfo.ctor = env->GetMethodID(surfPlaneClassInfo.clazz, "", - "(Landroid/media/ImageReader$SurfaceImage;III)V"); - LOG_ALWAYS_FATAL_IF(surfPlaneClassInfo.ctor == NULL, "Can not find SurfacePlane constructor"); + gSurfacePlaneClassInfo.clazz = (jclass) env->NewGlobalRef(planeClazz); + gSurfacePlaneClassInfo.ctor = env->GetMethodID(gSurfacePlaneClassInfo.clazz, "", + "(Landroid/media/ImageReader$SurfaceImage;III)V"); + LOG_ALWAYS_FATAL_IF(gSurfacePlaneClassInfo.ctor == NULL, + "Can not find SurfacePlane constructor"); } static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, @@ -662,8 +667,8 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, int imageReaderWidth = ctx->getBufferWidth(); int imageReaderHeight = ctx->getBufferHeight(); - if ((imageReaderWidth != outputWidth) || - (imageReaderHeight != outputHeight)) { + if (imageReaderWidth != outputWidth + || imageReaderHeight != outputHeight) { // Spew warning for now, since MediaCodec decoder has a bug to setup the right crop // TODO: make it throw exception once the decoder bug is fixed. ALOGW("Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d", @@ -678,14 +683,18 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, // Throw exception ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x", buffer->format, ctx->getBufferFormat()); + String8 msg; + msg.appendFormat("The producer output buffer format 0x%x doesn't " + "match the ImageReader's configured buffer format 0x%x.", + buffer->format, ctx->getBufferFormat()); jniThrowException(env, "java/lang/UnsupportedOperationException", - "The producer output buffer configuration doesn't match the ImageReader" - "configured"); + msg.string()); return false; } // Set SurfaceImage instance member variables Image_setBuffer(env, image, buffer); - env->SetLongField(image, fields.timeStamp, static_cast(buffer->timestamp)); + env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp, + static_cast(buffer->timestamp)); return true; } @@ -701,8 +710,8 @@ static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz) } // Wrap the IGBP in a Java-language Surface. - return android_view_Surface_createFromIGraphicBufferProducer(env, - consumer->getProducerInterface()); + return android_view_Surface_createFromIGraphicBufferProducer( + env, consumer->getProducerInterface()); } static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx) @@ -719,8 +728,8 @@ static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx) rowStride = Image_imageGetRowStride(env, buffer, idx); pixelStride = Image_imageGetPixelStride(env, buffer, idx); - jobject surfPlaneObj = env->NewObject(surfPlaneClassInfo.clazz, surfPlaneClassInfo.ctor, - thiz, idx, rowStride, pixelStride); + jobject surfPlaneObj = env->NewObject(gSurfacePlaneClassInfo.clazz, + gSurfacePlaneClassInfo.ctor, thiz, idx, rowStride, pixelStride); return surfPlaneObj; } -- cgit v1.1 From 708e3595031fa15f4ac26c5675a53c1ed495b895 Mon Sep 17 00:00:00 2001 From: Zhijun He Date: Mon, 5 Aug 2013 14:56:11 -0700 Subject: ImageReader: Add RGB format support. Bug: 10155122 Change-Id: Id53d6ec815488e73bde6ca62b42c92d16bc813c9 --- media/jni/android_media_ImageReader.cpp | 48 +++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'media/jni') diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index c1c965a..0646f98 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -305,6 +305,7 @@ static void Image_getLockedBufferInfo(JNIEnv* env, CpuConsumer::LockedBuffer* bu uint32_t dataSize, ySize, cSize, cStride; uint8_t *cb, *cr; uint8_t *pData = NULL; + int bytesPerPixel = 0; dataSize = ySize = cSize = cStride = 0; int32_t fmt = buffer->format; @@ -385,6 +386,28 @@ static void Image_getLockedBufferInfo(JNIEnv* env, CpuConsumer::LockedBuffer* bu pData = buffer->data; dataSize = buffer->width * 2 * buffer->height; break; + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + // Single plane, 32bpp. + bytesPerPixel = 4; + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + pData = buffer->data; + dataSize = buffer->stride * buffer->height * bytesPerPixel; + break; + case HAL_PIXEL_FORMAT_RGB_565: + // Single plane, 16bpp. + bytesPerPixel = 2; + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + pData = buffer->data; + dataSize = buffer->stride * buffer->height * bytesPerPixel; + break; + case HAL_PIXEL_FORMAT_RGB_888: + // Single plane, 24bpp. + bytesPerPixel = 3; + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + pData = buffer->data; + dataSize = buffer->stride * buffer->height * bytesPerPixel; + break; default: jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException", "Pixel format: 0x%x is unsupported", fmt); @@ -426,10 +449,21 @@ static jint Image_imageGetPixelStride(JNIEnv* env, CpuConsumer::LockedBuffer* bu break; case HAL_PIXEL_FORMAT_Y16: case HAL_PIXEL_FORMAT_RAW_SENSOR: + case HAL_PIXEL_FORMAT_RGB_565: // Single plane 16bpp data. ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); pixelStride = 2; break; + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + pixelStride = 4; + break; + case HAL_PIXEL_FORMAT_RGB_888: + // Single plane, 24bpp. + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + pixelStride = 3; + break; default: jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException", "Pixel format: 0x%x is unsupported", fmt); @@ -482,6 +516,20 @@ static jint Image_imageGetRowStride(JNIEnv* env, CpuConsumer::LockedBuffer* buff "Stride is not 16 pixel aligned %d", buffer->stride); rowStride = buffer->stride * 2; break; + case HAL_PIXEL_FORMAT_RGB_565: + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + rowStride = buffer->stride * 2; + break; + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + rowStride = buffer->stride * 4; + break; + case HAL_PIXEL_FORMAT_RGB_888: + // Single plane, 24bpp. + ALOG_ASSERT(idx == 0, "Wrong index: %d", idx); + rowStride = buffer->stride * 3; + break; default: ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt); jniThrowException(env, "java/lang/UnsupportedOperationException", -- cgit v1.1 From 52a9a10b6b8c7b7a9f97777541841b94d4fd9754 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 2 Aug 2013 01:38:38 -0700 Subject: Clearly separate consumer and producer interfaces Bug: 9265647 Change-Id: Ic68e91788d0a05251e1d2fb9f9d4de403c7099bf --- media/jni/android_media_ImageReader.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'media/jni') diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index ecc180c..0b429f6 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -78,9 +78,11 @@ public: void returnLockedBuffer(CpuConsumer::LockedBuffer* buffer); + void setCpuConsumer(const sp& consumer) { mConsumer = consumer; } CpuConsumer* getCpuConsumer() { return mConsumer.get(); } - void setCpuConsumer(sp consumer) { mConsumer = consumer; } + void setBufferQueue(const sp& bq) { mBufferQueue = bq; } + BufferQueue* getBufferQueue() { return mBufferQueue.get(); } void setBufferFormat(int format) { mFormat = format; } int getBufferFormat() { return mFormat; } @@ -97,6 +99,7 @@ private: List mBuffers; sp mConsumer; + sp mBufferQueue; jobject mWeakThiz; jclass mClazz; int mFormat; @@ -214,6 +217,17 @@ static CpuConsumer* ImageReader_getCpuConsumer(JNIEnv* env, jobject thiz) return ctx->getCpuConsumer(); } +static BufferQueue* ImageReader_getBufferQueue(JNIEnv* env, jobject thiz) +{ + ALOGV("%s:", __FUNCTION__); + JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz); + if (ctx == NULL) { + jniThrowRuntimeException(env, "ImageReaderContext is not initialized"); + return NULL; + } + return ctx->getBufferQueue(); +} + static void ImageReader_setNativeContext(JNIEnv* env, jobject thiz, sp ctx) { @@ -609,6 +623,7 @@ static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, } sp ctx(new JNIImageReaderContext(env, weakThiz, clazz, maxImages)); ctx->setCpuConsumer(consumer); + ctx->setBufferQueue(bq); consumer->setFrameAvailableListener(ctx); ImageReader_setNativeContext(env, thiz, ctx); ctx->setBufferFormat(nativeFormat); @@ -751,15 +766,14 @@ static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz) { ALOGV("%s: ", __FUNCTION__); - CpuConsumer* consumer = ImageReader_getCpuConsumer(env, thiz); - if (consumer == NULL) { + BufferQueue* bq = ImageReader_getBufferQueue(env, thiz); + if (bq == NULL) { jniThrowRuntimeException(env, "CpuConsumer is uninitialized"); return NULL; } // Wrap the IGBP in a Java-language Surface. - return android_view_Surface_createFromIGraphicBufferProducer( - env, consumer->getProducerInterface()); + return android_view_Surface_createFromIGraphicBufferProducer(env, bq); } static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx) -- cgit v1.1 From f724c277d3362dbc8099fcbf8674609a424cd2ee Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Wed, 7 Aug 2013 14:17:04 -0700 Subject: Add more virtual display tests. We can't test everything in CTS because some features require system permissions. So this is another copy of the CTS test with more stuff that we can build with the system cert. Change-Id: Ied5a456a0810d38d307b6dfbad0f770cb480b4ee --- media/jni/android_media_ImageReader.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'media/jni') diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 0b429f6..cd589de 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -701,11 +701,12 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, } status_t res = consumer->lockNextBuffer(buffer); if (res != NO_ERROR) { - ALOGE("%s Fail to lockNextBuffer with error: %d ", __FUNCTION__, res); + if (res != BAD_VALUE /*no buffers*/) { + ALOGE("%s Fail to lockNextBuffer with error: %d ", __FUNCTION__, res); + } return false; } - // Check if the left-top corner of the crop rect is origin, we currently assume this point is // zero, will revist this once this assumption turns out problematic. Point lt = buffer->crop.leftTop(); -- cgit v1.1 From 8d5f3e31c914e29129f50fe9830d71adf52ab5cf Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Mon, 12 Aug 2013 09:19:45 -0700 Subject: Manage jclass objects (and most jobjects) in jni code using ScopedLocalRef for safer refcounting. Previously jclass objects were not DeleteLocalRef'ed at all, leading us to exhaust the local ref pool quickly in certain circumstances. This change also makes sure we properly serialize int64_t entries when converting from AMessage to HashMap and boosts thread priority for java-instantiated MediaCodecs slightly from NORMAL to FOREGROUND. Change-Id: I4ebdd8a5ca6b3442698c9f86fcc31af8c199aaf5 --- media/jni/android_media_MediaCodec.cpp | 80 ++++++++++++++++------------ media/jni/android_media_Utils.cpp | 97 +++++++++++++++++++--------------- 2 files changed, 101 insertions(+), 76 deletions(-) (limited to 'media/jni') diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 8689e19..ae1db87 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -38,6 +38,8 @@ #include #include +#include + #include namespace android { @@ -86,7 +88,7 @@ JMediaCodec::JMediaCodec( mLooper->start( false, // runOnCallingThread false, // canCallJava - PRIORITY_DEFAULT); + PRIORITY_FOREGROUND); if (nameIsType) { mCodec = MediaCodec::CreateByType(mLooper, name, encoder); @@ -186,9 +188,10 @@ status_t JMediaCodec::dequeueOutputBuffer( return err; } - jclass clazz = env->FindClass("android/media/MediaCodec$BufferInfo"); + ScopedLocalRef clazz( + env, env->FindClass("android/media/MediaCodec$BufferInfo")); - jmethodID method = env->GetMethodID(clazz, "set", "(IIJI)V"); + jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V"); env->CallVoidMethod(bufferInfo, method, offset, size, timeUs, flags); return OK; @@ -227,29 +230,33 @@ status_t JMediaCodec::getBuffers( return err; } - jclass byteBufferClass = env->FindClass("java/nio/ByteBuffer"); - CHECK(byteBufferClass != NULL); + ScopedLocalRef byteBufferClass( + env, env->FindClass("java/nio/ByteBuffer")); + + CHECK(byteBufferClass.get() != NULL); jmethodID orderID = env->GetMethodID( - byteBufferClass, + byteBufferClass.get(), "order", "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"); CHECK(orderID != NULL); - jclass byteOrderClass = env->FindClass("java/nio/ByteOrder"); - CHECK(byteOrderClass != NULL); + ScopedLocalRef byteOrderClass( + env, env->FindClass("java/nio/ByteOrder")); + + CHECK(byteOrderClass.get() != NULL); jmethodID nativeOrderID = env->GetStaticMethodID( - byteOrderClass, "nativeOrder", "()Ljava/nio/ByteOrder;"); + byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;"); CHECK(nativeOrderID != NULL); jobject nativeByteOrderObj = - env->CallStaticObjectMethod(byteOrderClass, nativeOrderID); + env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID); CHECK(nativeByteOrderObj != NULL); *bufArray = (jobjectArray)env->NewObjectArray( - buffers.size(), byteBufferClass, NULL); + buffers.size(), byteBufferClass.get(), NULL); if (*bufArray == NULL) { env->DeleteLocalRef(nativeByteOrderObj); return NO_MEMORY; @@ -338,11 +345,12 @@ static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) { } static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) { - jclass clazz = env->FindClass("android/media/MediaCodec$CryptoException"); - CHECK(clazz != NULL); + ScopedLocalRef clazz( + env, env->FindClass("android/media/MediaCodec$CryptoException")); + CHECK(clazz.get() != NULL); jmethodID constructID = - env->GetMethodID(clazz, "", "(ILjava/lang/String;)V"); + env->GetMethodID(clazz.get(), "", "(ILjava/lang/String;)V"); CHECK(constructID != NULL); jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error"); @@ -363,7 +371,7 @@ static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) { } jthrowable exception = - (jthrowable)env->NewObject(clazz, constructID, err, msgObj); + (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj); env->Throw(exception); } @@ -848,51 +856,55 @@ static void android_media_MediaCodec_setVideoScalingMode( } static void android_media_MediaCodec_native_init(JNIEnv *env) { - jclass clazz = env->FindClass("android/media/MediaCodec"); - CHECK(clazz != NULL); + ScopedLocalRef clazz( + env, env->FindClass("android/media/MediaCodec")); + CHECK(clazz.get() != NULL); - gFields.context = env->GetFieldID(clazz, "mNativeContext", "I"); + gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "I"); CHECK(gFields.context != NULL); - clazz = env->FindClass("android/media/MediaCodec$CryptoInfo"); - CHECK(clazz != NULL); + clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo")); + CHECK(clazz.get() != NULL); gFields.cryptoInfoNumSubSamplesID = - env->GetFieldID(clazz, "numSubSamples", "I"); + env->GetFieldID(clazz.get(), "numSubSamples", "I"); CHECK(gFields.cryptoInfoNumSubSamplesID != NULL); gFields.cryptoInfoNumBytesOfClearDataID = - env->GetFieldID(clazz, "numBytesOfClearData", "[I"); + env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I"); CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL); gFields.cryptoInfoNumBytesOfEncryptedDataID = - env->GetFieldID(clazz, "numBytesOfEncryptedData", "[I"); + env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I"); CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL); - gFields.cryptoInfoKeyID = env->GetFieldID(clazz, "key", "[B"); + gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B"); CHECK(gFields.cryptoInfoKeyID != NULL); - gFields.cryptoInfoIVID = env->GetFieldID(clazz, "iv", "[B"); + gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B"); CHECK(gFields.cryptoInfoIVID != NULL); - gFields.cryptoInfoModeID = env->GetFieldID(clazz, "mode", "I"); + gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I"); CHECK(gFields.cryptoInfoModeID != NULL); - clazz = env->FindClass("android/media/MediaCodec$CryptoException"); - CHECK(clazz != NULL); + clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException")); + CHECK(clazz.get() != NULL); jfieldID field; - field = env->GetStaticFieldID(clazz, "ERROR_NO_KEY", "I"); + field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I"); CHECK(field != NULL); - gCryptoErrorCodes.cryptoErrorNoKey = env->GetStaticIntField(clazz, field); + gCryptoErrorCodes.cryptoErrorNoKey = + env->GetStaticIntField(clazz.get(), field); - field = env->GetStaticFieldID(clazz, "ERROR_KEY_EXPIRED", "I"); + field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I"); CHECK(field != NULL); - gCryptoErrorCodes.cryptoErrorKeyExpired = env->GetStaticIntField(clazz, field); + gCryptoErrorCodes.cryptoErrorKeyExpired = + env->GetStaticIntField(clazz.get(), field); - field = env->GetStaticFieldID(clazz, "ERROR_RESOURCE_BUSY", "I"); + field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I"); CHECK(field != NULL); - gCryptoErrorCodes.cryptoErrorResourceBusy = env->GetStaticIntField(clazz, field); + gCryptoErrorCodes.cryptoErrorResourceBusy = + env->GetStaticIntField(clazz.get(), field); } static void android_media_MediaCodec_native_setup( diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp index e35ace3..54c5e9b 100644 --- a/media/jni/android_media_Utils.cpp +++ b/media/jni/android_media_Utils.cpp @@ -24,6 +24,8 @@ #include #include +#include + namespace android { bool ConvertKeyValueArraysToKeyedVector( @@ -76,33 +78,35 @@ bool ConvertKeyValueArraysToKeyedVector( } static jobject makeIntegerObject(JNIEnv *env, int32_t value) { - jclass clazz = env->FindClass("java/lang/Integer"); - CHECK(clazz != NULL); + ScopedLocalRef clazz(env, env->FindClass("java/lang/Integer")); + CHECK(clazz.get() != NULL); - jmethodID integerConstructID = env->GetMethodID(clazz, "", "(I)V"); + jmethodID integerConstructID = + env->GetMethodID(clazz.get(), "", "(I)V"); CHECK(integerConstructID != NULL); - return env->NewObject(clazz, integerConstructID, value); + return env->NewObject(clazz.get(), integerConstructID, value); } static jobject makeLongObject(JNIEnv *env, int64_t value) { - jclass clazz = env->FindClass("java/lang/Long"); - CHECK(clazz != NULL); + ScopedLocalRef clazz(env, env->FindClass("java/lang/Long")); + CHECK(clazz.get() != NULL); - jmethodID longConstructID = env->GetMethodID(clazz, "", "(J)V"); + jmethodID longConstructID = env->GetMethodID(clazz.get(), "", "(J)V"); CHECK(longConstructID != NULL); - return env->NewObject(clazz, longConstructID, value); + return env->NewObject(clazz.get(), longConstructID, value); } static jobject makeFloatObject(JNIEnv *env, float value) { - jclass clazz = env->FindClass("java/lang/Float"); - CHECK(clazz != NULL); + ScopedLocalRef clazz(env, env->FindClass("java/lang/Float")); + CHECK(clazz.get() != NULL); - jmethodID floatConstructID = env->GetMethodID(clazz, "", "(F)V"); + jmethodID floatConstructID = + env->GetMethodID(clazz.get(), "", "(F)V"); CHECK(floatConstructID != NULL); - return env->NewObject(clazz, floatConstructID, value); + return env->NewObject(clazz.get(), floatConstructID, value); } static jobject makeByteBufferObject( @@ -110,15 +114,16 @@ static jobject makeByteBufferObject( jbyteArray byteArrayObj = env->NewByteArray(size); env->SetByteArrayRegion(byteArrayObj, 0, size, (const jbyte *)data); - jclass clazz = env->FindClass("java/nio/ByteBuffer"); - CHECK(clazz != NULL); + ScopedLocalRef clazz(env, env->FindClass("java/nio/ByteBuffer")); + CHECK(clazz.get() != NULL); jmethodID byteBufWrapID = - env->GetStaticMethodID(clazz, "wrap", "([B)Ljava/nio/ByteBuffer;"); + env->GetStaticMethodID( + clazz.get(), "wrap", "([B)Ljava/nio/ByteBuffer;"); CHECK(byteBufWrapID != NULL); jobject byteBufObj = env->CallStaticObjectMethod( - clazz, byteBufWrapID, byteArrayObj); + clazz.get(), byteBufWrapID, byteArrayObj); env->DeleteLocalRef(byteArrayObj); byteArrayObj = NULL; @@ -140,14 +145,15 @@ static void SetMapInt32( status_t ConvertMessageToMap( JNIEnv *env, const sp &msg, jobject *map) { - jclass hashMapClazz = env->FindClass("java/util/HashMap"); + ScopedLocalRef hashMapClazz( + env, env->FindClass("java/util/HashMap")); - if (hashMapClazz == NULL) { + if (hashMapClazz.get() == NULL) { return -EINVAL; } jmethodID hashMapConstructID = - env->GetMethodID(hashMapClazz, "", "()V"); + env->GetMethodID(hashMapClazz.get(), "", "()V"); if (hashMapConstructID == NULL) { return -EINVAL; @@ -155,7 +161,7 @@ status_t ConvertMessageToMap( jmethodID hashMapPutID = env->GetMethodID( - hashMapClazz, + hashMapClazz.get(), "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); @@ -163,7 +169,7 @@ status_t ConvertMessageToMap( return -EINVAL; } - jobject hashMap = env->NewObject(hashMapClazz, hashMapConstructID); + jobject hashMap = env->NewObject(hashMapClazz.get(), hashMapConstructID); for (size_t i = 0; i < msg->countEntries(); ++i) { AMessage::Type valueType; @@ -276,17 +282,16 @@ status_t ConvertMessageToMap( status_t ConvertKeyValueArraysToMessage( JNIEnv *env, jobjectArray keys, jobjectArray values, sp *out) { - jclass stringClass = env->FindClass("java/lang/String"); - CHECK(stringClass != NULL); - - jclass integerClass = env->FindClass("java/lang/Integer"); - CHECK(integerClass != NULL); - - jclass floatClass = env->FindClass("java/lang/Float"); - CHECK(floatClass != NULL); - - jclass byteBufClass = env->FindClass("java/nio/ByteBuffer"); - CHECK(byteBufClass != NULL); + ScopedLocalRef stringClass(env, env->FindClass("java/lang/String")); + CHECK(stringClass.get() != NULL); + ScopedLocalRef integerClass(env, env->FindClass("java/lang/Integer")); + CHECK(integerClass.get() != NULL); + ScopedLocalRef longClass(env, env->FindClass("java/lang/Long")); + CHECK(longClass.get() != NULL); + ScopedLocalRef floatClass(env, env->FindClass("java/lang/Float")); + CHECK(floatClass.get() != NULL); + ScopedLocalRef byteBufClass(env, env->FindClass("java/nio/ByteBuffer")); + CHECK(byteBufClass.get() != NULL); sp msg = new AMessage; @@ -309,7 +314,7 @@ status_t ConvertKeyValueArraysToMessage( for (jsize i = 0; i < numEntries; ++i) { jobject keyObj = env->GetObjectArrayElement(keys, i); - if (!env->IsInstanceOf(keyObj, stringClass)) { + if (!env->IsInstanceOf(keyObj, stringClass.get())) { return -EINVAL; } @@ -326,7 +331,7 @@ status_t ConvertKeyValueArraysToMessage( jobject valueObj = env->GetObjectArrayElement(values, i); - if (env->IsInstanceOf(valueObj, stringClass)) { + if (env->IsInstanceOf(valueObj, stringClass.get())) { const char *value = env->GetStringUTFChars((jstring)valueObj, NULL); if (value == NULL) { @@ -337,29 +342,37 @@ status_t ConvertKeyValueArraysToMessage( env->ReleaseStringUTFChars((jstring)valueObj, value); value = NULL; - } else if (env->IsInstanceOf(valueObj, integerClass)) { + } else if (env->IsInstanceOf(valueObj, integerClass.get())) { jmethodID intValueID = - env->GetMethodID(integerClass, "intValue", "()I"); + env->GetMethodID(integerClass.get(), "intValue", "()I"); CHECK(intValueID != NULL); jint value = env->CallIntMethod(valueObj, intValueID); msg->setInt32(key.c_str(), value); - } else if (env->IsInstanceOf(valueObj, floatClass)) { + } else if (env->IsInstanceOf(valueObj, longClass.get())) { + jmethodID longValueID = + env->GetMethodID(longClass.get(), "longValue", "()J"); + CHECK(longValueID != NULL); + + jlong value = env->CallLongMethod(valueObj, longValueID); + + msg->setInt64(key.c_str(), value); + } else if (env->IsInstanceOf(valueObj, floatClass.get())) { jmethodID floatValueID = - env->GetMethodID(floatClass, "floatValue", "()F"); + env->GetMethodID(floatClass.get(), "floatValue", "()F"); CHECK(floatValueID != NULL); jfloat value = env->CallFloatMethod(valueObj, floatValueID); msg->setFloat(key.c_str(), value); - } else if (env->IsInstanceOf(valueObj, byteBufClass)) { + } else if (env->IsInstanceOf(valueObj, byteBufClass.get())) { jmethodID positionID = - env->GetMethodID(byteBufClass, "position", "()I"); + env->GetMethodID(byteBufClass.get(), "position", "()I"); CHECK(positionID != NULL); jmethodID limitID = - env->GetMethodID(byteBufClass, "limit", "()I"); + env->GetMethodID(byteBufClass.get(), "limit", "()I"); CHECK(limitID != NULL); jint position = env->CallIntMethod(valueObj, positionID); @@ -375,7 +388,7 @@ status_t ConvertKeyValueArraysToMessage( buffer->size()); } else { jmethodID arrayID = - env->GetMethodID(byteBufClass, "array", "()[B"); + env->GetMethodID(byteBufClass.get(), "array", "()[B"); CHECK(arrayID != NULL); jbyteArray byteArray = -- cgit v1.1 From 226065bbe60cf32b33a5f86d27e2db88138e4486 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Mon, 12 Aug 2013 10:14:11 -0700 Subject: Expose MediaCodec.setParameters API to - change video target bitrate on the fly - request sync frames - temporarily suspend feeding input buffers to the encoder Change-Id: If5cf1162b2eeb28ac08288ecfa9f0e9823dd972e --- media/jni/android_media_MediaCodec.cpp | 28 ++++++++++++++++++++++++++++ media/jni/android_media_MediaCodec.h | 2 ++ 2 files changed, 30 insertions(+) (limited to 'media/jni') diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index ae1db87..a859506 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -310,6 +310,10 @@ status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const { return OK; } +status_t JMediaCodec::setParameters(const sp &msg) { + return mCodec->setParameters(msg); +} + void JMediaCodec::setVideoScalingMode(int mode) { if (mSurfaceTextureClient != NULL) { native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode); @@ -837,6 +841,27 @@ static jobject android_media_MediaCodec_getName( return NULL; } +static void android_media_MediaCodec_setParameters( + JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) { + ALOGV("android_media_MediaCodec_setParameters"); + + sp codec = getMediaCodec(env, thiz); + + if (codec == NULL) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return; + } + + sp params; + status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, ¶ms); + + if (err == OK) { + err = codec->setParameters(params); + } + + throwExceptionAsNecessary(env, err); +} + static void android_media_MediaCodec_setVideoScalingMode( JNIEnv *env, jobject thiz, jint mode) { sp codec = getMediaCodec(env, thiz); @@ -986,6 +1011,9 @@ static JNINativeMethod gMethods[] = { { "getName", "()Ljava/lang/String;", (void *)android_media_MediaCodec_getName }, + { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V", + (void *)android_media_MediaCodec_setParameters }, + { "setVideoScalingMode", "(I)V", (void *)android_media_MediaCodec_setVideoScalingMode }, diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h index 282d2c5..2fbbd72 100644 --- a/media/jni/android_media_MediaCodec.h +++ b/media/jni/android_media_MediaCodec.h @@ -87,6 +87,8 @@ struct JMediaCodec : public RefBase { status_t getName(JNIEnv *env, jstring *name) const; + status_t setParameters(const sp ¶ms); + void setVideoScalingMode(int mode); protected: -- cgit v1.1 From 80c4437ebfe3e679267a64e4c9d7bdd585b7afce Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Fri, 10 May 2013 09:24:12 -0700 Subject: MediaCodecInfo.java: Added isFeatureSupported method to CodecCapabilities Added isFeatureSupported method to CodecCapabilities, so that applications can query whether codecs support various features. For now added one video-decoder feature: FEATURE_AdaptivePlayback Media playback applications can query it to see if the codec supports seamless resolution changes during decoding. Change-Id: I56b2cf1429f39f9b9e0243a990c95e7a64dd7ff7 Signed-off-by: Lajos Molnar Related-to-bug: 7093648 --- media/jni/android_media_MediaCodecList.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'media/jni') diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp index 04430ec..caa594e 100644 --- a/media/jni/android_media_MediaCodecList.cpp +++ b/media/jni/android_media_MediaCodecList.cpp @@ -110,10 +110,11 @@ static jobject android_media_MediaCodecList_getCodecCapabilities( Vector profileLevels; Vector colorFormats; + uint32_t flags; status_t err = MediaCodecList::getInstance()->getCodecCapabilities( - index, typeStr, &profileLevels, &colorFormats); + index, typeStr, &profileLevels, &colorFormats, &flags); env->ReleaseStringUTFChars(type, typeStr); typeStr = NULL; @@ -127,6 +128,9 @@ static jobject android_media_MediaCodecList_getCodecCapabilities( env->FindClass("android/media/MediaCodecInfo$CodecCapabilities"); CHECK(capsClazz != NULL); + jfieldID flagsField = + env->GetFieldID(capsClazz, "flags", "I"); + jobject caps = env->AllocObject(capsClazz); jclass profileLevelClazz = @@ -163,6 +167,8 @@ static jobject android_media_MediaCodecList_getCodecCapabilities( env->SetObjectField(caps, profileLevelsField, profileLevelArray); + env->SetIntField(caps, flagsField, flags); + env->DeleteLocalRef(profileLevelArray); profileLevelArray = NULL; -- cgit v1.1 From dd0643202de80cc4ced37d1844e722c8a5e89154 Mon Sep 17 00:00:00 2001 From: Igor Murashkin Date: Wed, 14 Aug 2013 19:05:17 -0700 Subject: media: Fix ImageReader only using maxImages=1 no matter what - No longer return null when some bad error happens - Throws OutOfResourcesException when images need to be closed - Throws IllegalStateException when an unknown internal error happens Bug: 10333400 Change-Id: Ia53a5dd33f9ce53abd036e080e6fcc4ded9b251d --- media/jni/android_media_ImageReader.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'media/jni') diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index cd589de..7d914d2 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -44,6 +44,9 @@ using namespace android; +static const char* const OutOfResourcesException = + "android/view/Surface$OutOfResourcesException"; + enum { IMAGE_READER_MAX_NUM_PLANES = 3, }; @@ -609,7 +612,8 @@ static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, nativeFormat = Image_getPixelFormat(env, format); sp bq = new BufferQueue(); - sp consumer = new CpuConsumer(bq, true, maxImages); + sp consumer = new CpuConsumer(bq, maxImages, + /*controlledByApp*/true); // TODO: throw dvm exOutOfMemoryError? if (consumer == NULL) { jniThrowRuntimeException(env, "Failed to allocate native CpuConsumer"); @@ -702,7 +706,17 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, status_t res = consumer->lockNextBuffer(buffer); if (res != NO_ERROR) { if (res != BAD_VALUE /*no buffers*/) { - ALOGE("%s Fail to lockNextBuffer with error: %d ", __FUNCTION__, res); + if (res == NOT_ENOUGH_DATA) { + jniThrowException(env, OutOfResourcesException, + "Too many outstanding images, close existing images" + " to be able to acquire more."); + } else { + ALOGE("%s Fail to lockNextBuffer with error: %d ", + __FUNCTION__, res); + jniThrowExceptionFmt(env, "java/lang/IllegalStateException", + "Unknown error (%d) when we tried to lock buffer.", + res); + } } return false; } @@ -714,6 +728,7 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, ALOGE("crop left: %d, top = %d", lt.x, lt.y); jniThrowException(env, "java/lang/UnsupportedOperationException", "crop left top corner need to at origin"); + return false; } // Check if the producer buffer configurations match what ImageReader configured. -- cgit v1.1 From 8117d8f7023f8981bc4b2651efed5b28104d83d3 Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Fri, 16 Aug 2013 13:46:02 -0700 Subject: Fix JNI method called with exception pending bug: 10313912 Change-Id: I8390905334f2e37f210adced52c31e7a431d4f55 --- media/jni/android_media_MediaDrm.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'media/jni') diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index 16a1e48..60142cd 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -753,7 +753,9 @@ static jbyteArray android_media_MediaDrm_provideKeyResponse( status_t err = drm->provideKeyResponse(sessionId, response, keySetId); - throwExceptionAsNecessary(env, err, "Failed to handle key response"); + if (throwExceptionAsNecessary(env, err, "Failed to handle key response")) { + return NULL; + } return VectorToJByteArray(env, keySetId); } @@ -1104,7 +1106,9 @@ static jbyteArray android_media_MediaDrm_encryptNative( status_t err = drm->encrypt(sessionId, keyId, input, iv, output); - throwExceptionAsNecessary(env, err, "Failed to encrypt"); + if (throwExceptionAsNecessary(env, err, "Failed to encrypt")) { + return NULL; + } return VectorToJByteArray(env, output); } @@ -1132,7 +1136,9 @@ static jbyteArray android_media_MediaDrm_decryptNative( Vector output; status_t err = drm->decrypt(sessionId, keyId, input, iv, output); - throwExceptionAsNecessary(env, err, "Failed to decrypt"); + if (throwExceptionAsNecessary(env, err, "Failed to decrypt")) { + return NULL; + } return VectorToJByteArray(env, output); } @@ -1160,7 +1166,9 @@ static jbyteArray android_media_MediaDrm_signNative( status_t err = drm->sign(sessionId, keyId, message, signature); - throwExceptionAsNecessary(env, err, "Failed to sign"); + if (throwExceptionAsNecessary(env, err, "Failed to sign")) { + return NULL; + } return VectorToJByteArray(env, signature); } -- cgit v1.1 From 7cda491321b9bd2e8faf956824312ea6a30e6457 Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Wed, 21 Aug 2013 11:52:34 -0700 Subject: Add ability to test supported content types to MediaDrm bug: 10244066 Change-Id: Ic96c2e23f36809faf1c88ede500f4bc2bad4142a --- media/jni/android_media_MediaDrm.cpp | 15 ++++++++++----- media/jni/android_media_MediaDrm.h | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'media/jni') diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index 60142cd..666d111 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -348,14 +348,14 @@ void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) // static -bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16]) { +bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) { sp drm = MakeDrm(); if (drm == NULL) { return false; } - return drm->isCryptoSchemeSupported(uuid); + return drm->isCryptoSchemeSupported(uuid, mimeType); } status_t JDrm::initCheck() const { @@ -611,7 +611,7 @@ static void android_media_MediaDrm_native_finalize( } static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative( - JNIEnv *env, jobject thiz, jbyteArray uuidObj) { + JNIEnv *env, jobject thiz, jbyteArray uuidObj, jstring jmimeType) { if (uuidObj == NULL) { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); @@ -628,7 +628,12 @@ static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative( return false; } - return JDrm::IsCryptoSchemeSupported(uuid.array()); + String8 mimeType; + if (jmimeType != NULL) { + mimeType = JStringToString8(env, jmimeType); + } + + return JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType); } static jbyteArray android_media_MediaDrm_openSession( @@ -1212,7 +1217,7 @@ static JNINativeMethod gMethods[] = { { "native_finalize", "()V", (void *)android_media_MediaDrm_native_finalize }, - { "isCryptoSchemeSupportedNative", "([B)Z", + { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z", (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative }, { "openSession", "()[B", diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h index 9b3917f..620ad28 100644 --- a/media/jni/android_media_MediaDrm.h +++ b/media/jni/android_media_MediaDrm.h @@ -37,7 +37,7 @@ public: }; struct JDrm : public BnDrmClient { - static bool IsCryptoSchemeSupported(const uint8_t uuid[16]); + static bool IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType); JDrm(JNIEnv *env, jobject thiz, const uint8_t uuid[16]); -- cgit v1.1 From af753a2dfc66c92bfcac64b77c7a4d89d9434ad8 Mon Sep 17 00:00:00 2001 From: Zhijun He Date: Fri, 23 Aug 2013 09:17:29 -0700 Subject: ImageReader: Fix API doc table misalignment issue Also cleanup unused macro in ImageReader. Bug: 10360518 Change-Id: I2332703c92df771a6339ff92069e92d50a6c5cd5 --- media/jni/android_media_ImageReader.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'media/jni') diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 7d914d2..7f1d946 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -35,7 +35,6 @@ #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) ) -#define ANDROID_MEDIA_IMAGEREADER_JNI_ID "mCpuConsumer" #define ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID "mNativeContext" #define ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID "mLockedBuffer" #define ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID "mTimestamp" -- cgit v1.1 From d901c033756b01f5bd3c697fb3802331e9b45ad0 Mon Sep 17 00:00:00 2001 From: Igor Murashkin Date: Tue, 27 Aug 2013 15:19:55 -0700 Subject: media: ImageReader throws OutOfResourcesException when out of buffers Bug: 10507939 Change-Id: I34c66485695ad6141388be85903cbecb9ebaa5ab --- media/jni/android_media_ImageReader.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'media/jni') diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 7f1d946..92edb8a 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -155,7 +155,7 @@ CpuConsumer::LockedBuffer* JNIImageReaderContext::getLockedBuffer() { return buffer; } -void JNIImageReaderContext::returnLockedBuffer(CpuConsumer::LockedBuffer * buffer) { +void JNIImageReaderContext::returnLockedBuffer(CpuConsumer::LockedBuffer* buffer) { mBuffers.push_back(buffer); } @@ -698,8 +698,11 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, CpuConsumer* consumer = ctx->getCpuConsumer(); CpuConsumer::LockedBuffer* buffer = ctx->getLockedBuffer(); if (buffer == NULL) { - ALOGE("Unable to acquire a lockedBuffer, very likely client tries to lock more than" - "maxImages buffers"); + ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than" + " maxImages buffers"); + jniThrowException(env, OutOfResourcesException, + "Too many outstanding images, close existing images" + " to be able to acquire more."); return false; } status_t res = consumer->lockNextBuffer(buffer); -- cgit v1.1 From cfd47481d1b375663d4e8e8d0c292d9001aa384b Mon Sep 17 00:00:00 2001 From: Zhijun He Date: Mon, 9 Sep 2013 15:47:06 -0700 Subject: MediaMuxer: Add setLocation API This API could be used for camera recording when MediaMuxer is used to write output media file. Bug: 10594784 Change-Id: Ide2d6e1d87b246100a5def49bfb8646dc984a512 --- media/jni/android_media_MediaMuxer.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'media/jni') diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp index 7517e85..457b956 100644 --- a/media/jni/android_media_MediaMuxer.cpp +++ b/media/jni/android_media_MediaMuxer.cpp @@ -164,6 +164,18 @@ static void android_media_MediaMuxer_setOrientationHint( } +static void android_media_MediaMuxer_setLocation( + JNIEnv *env, jclass clazz, jint nativeObject, jint latitude, jint longitude) { + MediaMuxer* muxer = reinterpret_cast(nativeObject); + + status_t res = muxer->setLocation(latitude, longitude); + if (res != OK) { + jniThrowException(env, "java/lang/IllegalStateException", + "Failed to set location"); + return; + } +} + static void android_media_MediaMuxer_start(JNIEnv *env, jclass clazz, jint nativeObject) { sp muxer(reinterpret_cast(nativeObject)); @@ -216,6 +228,9 @@ static JNINativeMethod gMethods[] = { { "nativeSetOrientationHint", "(II)V", (void *)android_media_MediaMuxer_setOrientationHint}, + { "nativeSetLocation", "(III)V", + (void *)android_media_MediaMuxer_setLocation}, + { "nativeStart", "(I)V", (void *)android_media_MediaMuxer_start}, { "nativeWriteSampleData", "(IILjava/nio/ByteBuffer;IIJI)V", -- cgit v1.1 From 87eac99a21772ae56018cb81db6966557b459554 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Mon, 9 Sep 2013 17:44:59 -0700 Subject: Remove dependency on JNIHelp header side effects. Bug: 10680559 Change-Id: I47870d6c48906e0a420c52b7bc5945ffe29c68a2 --- media/jni/android_media_MediaDrm.cpp | 1 + media/jni/android_media_MediaExtractor.cpp | 1 + media/jni/android_media_MediaPlayer.cpp | 1 + media/jni/android_media_MediaScanner.cpp | 1 + media/jni/android_mtp_MtpDatabase.cpp | 1 + media/jni/android_mtp_MtpDevice.cpp | 1 + media/jni/mediaeditor/VideoEditorClasses.cpp | 1 + media/jni/mediaeditor/VideoEditorJava.cpp | 2 ++ media/jni/mediaeditor/VideoEditorLogging.h | 10 ++++++++++ media/jni/mediaeditor/VideoEditorOsal.cpp | 2 ++ media/jni/mediaeditor/VideoEditorPropertiesMain.cpp | 2 ++ 11 files changed, 23 insertions(+) (limited to 'media/jni') diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index 666d111..bbb74d2 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -21,6 +21,7 @@ #include "android_media_MediaDrm.h" #include "android_runtime/AndroidRuntime.h" +#include "android_runtime/Log.h" #include "android_os_Parcel.h" #include "jni.h" #include "JNIHelp.h" diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp index 1704d5c..1ac45d4 100644 --- a/media/jni/android_media_MediaExtractor.cpp +++ b/media/jni/android_media_MediaExtractor.cpp @@ -22,6 +22,7 @@ #include "android_media_Utils.h" #include "android_runtime/AndroidRuntime.h" +#include "android_runtime/Log.h" #include "jni.h" #include "JNIHelp.h" diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 9b66c06..d134667 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -31,6 +31,7 @@ #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" #include "android_runtime/android_view_Surface.h" +#include "android_runtime/Log.h" #include "utils/Errors.h" // for status_t #include "utils/KeyedVector.h" #include "utils/String8.h" diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp index 5d27966..4e3d14e 100644 --- a/media/jni/android_media_MediaScanner.cpp +++ b/media/jni/android_media_MediaScanner.cpp @@ -25,6 +25,7 @@ #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" +#include "android_runtime/Log.h" using namespace android; diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp index fbd5d21..77c7966 100644 --- a/media/jni/android_mtp_MtpDatabase.cpp +++ b/media/jni/android_mtp_MtpDatabase.cpp @@ -26,6 +26,7 @@ #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" +#include "android_runtime/Log.h" #include "MtpDatabase.h" #include "MtpDataPacket.h" diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp index 113784e..b61b66c 100644 --- a/media/jni/android_mtp_MtpDevice.cpp +++ b/media/jni/android_mtp_MtpDevice.cpp @@ -28,6 +28,7 @@ #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" +#include "android_runtime/Log.h" #include "private/android_filesystem_config.h" #include "MtpTypes.h" diff --git a/media/jni/mediaeditor/VideoEditorClasses.cpp b/media/jni/mediaeditor/VideoEditorClasses.cpp index 4982a47..d8099dd 100644 --- a/media/jni/mediaeditor/VideoEditorClasses.cpp +++ b/media/jni/mediaeditor/VideoEditorClasses.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#define LOG_TAG "VideoEditorClasses" #include #include diff --git a/media/jni/mediaeditor/VideoEditorJava.cpp b/media/jni/mediaeditor/VideoEditorJava.cpp index bcf9099..fde0fb5 100644 --- a/media/jni/mediaeditor/VideoEditorJava.cpp +++ b/media/jni/mediaeditor/VideoEditorJava.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define LOG_TAG "VideoEditorJava" + #include #include #include diff --git a/media/jni/mediaeditor/VideoEditorLogging.h b/media/jni/mediaeditor/VideoEditorLogging.h index 479d8b6..1f1228a 100644 --- a/media/jni/mediaeditor/VideoEditorLogging.h +++ b/media/jni/mediaeditor/VideoEditorLogging.h @@ -17,6 +17,16 @@ #ifndef VIDEO_EDITOR_LOGGING_H #define VIDEO_EDITOR_LOGGING_H +#ifndef LOG_TAG +#error "No LOG_TAG defined!" +#endif + +/* + * This file is used as a proxy for cutils/log.h. Include cutils/log.h here to + * avoid relying on import ordering. + */ +#include + //#define VIDEOEDIT_LOGGING_ENABLED #define VIDEOEDIT_LOG_INDENTATION (3) diff --git a/media/jni/mediaeditor/VideoEditorOsal.cpp b/media/jni/mediaeditor/VideoEditorOsal.cpp index a8c08ac..c12b1f5 100644 --- a/media/jni/mediaeditor/VideoEditorOsal.cpp +++ b/media/jni/mediaeditor/VideoEditorOsal.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define LOG_TAG "VideoEditorOsal" + #include #include #include diff --git a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp index c8fb263..2f8e357 100644 --- a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp +++ b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define LOG_TAG "VideoEditorPropertiesMain" + #include #include #include -- cgit v1.1 From 37682135da2fd90e7bc6a89a418862d1f4ca15fd Mon Sep 17 00:00:00 2001 From: Zhijun He Date: Tue, 10 Sep 2013 17:50:34 -0700 Subject: ImageReader: Skip size check for BLOB format HAL_PIXEL_FORMAT_BLOB is for JPEG capture, the buffer width/height by definition shouldn't be the same as the image width/height. Bug: 10360518 Change-Id: I32146a0e8e15439bb8fe199403db4ff37d1ab1af --- media/jni/android_media_ImageReader.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'media/jni') diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 92edb8a..94f20bc 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -738,7 +738,7 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, int outputWidth = buffer->width; int outputHeight = buffer->height; - // Correct with/height when crop is set. + // Correct width/height when crop is set. if (buffer->crop.getWidth() > 0) { outputWidth = buffer->crop.getWidth() + 1; } @@ -748,12 +748,19 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, int imageReaderWidth = ctx->getBufferWidth(); int imageReaderHeight = ctx->getBufferHeight(); - if (imageReaderWidth != outputWidth - || imageReaderHeight != outputHeight) { - // Spew warning for now, since MediaCodec decoder has a bug to setup the right crop - // TODO: make it throw exception once the decoder bug is fixed. - ALOGW("Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d", - outputWidth, outputHeight, imageReaderWidth, imageReaderHeight); + if ((buffer->format != HAL_PIXEL_FORMAT_BLOB) && + (imageReaderWidth != outputWidth || imageReaderHeight > outputHeight)) { + /** + * For video decoder, the buffer height is actually the vertical stride, + * which is always >= actual image height. For future, decoder need provide + * right crop rectangle to CpuConsumer to indicate the actual image height, + * see bug 9563986. After this bug is fixed, we can enforce the height equal + * check. Right now, only make sure buffer height is no less than ImageReader + * height. + */ + jniThrowExceptionFmt(env, "java/lang/IllegalStateException", + "Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d", + outputWidth, outputHeight, imageReaderWidth, imageReaderHeight); } if (ctx->getBufferFormat() != buffer->format) { -- cgit v1.1 From 5e712064dfe48992f8f732208fa4fc13f3455b30 Mon Sep 17 00:00:00 2001 From: Igor Murashkin Date: Thu, 29 Aug 2013 15:38:17 -0700 Subject: media: Update ImageReader APIs Bug: 10461757 Change-Id: Ic04e4c41965e3d417b29004f3f08e0cd56b8f4cb --- media/jni/android_media_ImageReader.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'media/jni') diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 94f20bc..56ae6b4 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -43,8 +43,8 @@ using namespace android; -static const char* const OutOfResourcesException = - "android/view/Surface$OutOfResourcesException"; +static const char* const MaxImagesAcquiredException = + "android/media/ImageReader$MaxImagesAcquiredException"; enum { IMAGE_READER_MAX_NUM_PLANES = 3, @@ -700,7 +700,7 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, if (buffer == NULL) { ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than" " maxImages buffers"); - jniThrowException(env, OutOfResourcesException, + jniThrowException(env, MaxImagesAcquiredException, "Too many outstanding images, close existing images" " to be able to acquire more."); return false; @@ -709,7 +709,7 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, if (res != NO_ERROR) { if (res != BAD_VALUE /*no buffers*/) { if (res == NOT_ENOUGH_DATA) { - jniThrowException(env, OutOfResourcesException, + jniThrowException(env, MaxImagesAcquiredException, "Too many outstanding images, close existing images" " to be able to acquire more."); } else { -- cgit v1.1 From e3351f1942bfe86682389b278e7ff128a72ea671 Mon Sep 17 00:00:00 2001 From: Igor Murashkin Date: Fri, 13 Sep 2013 13:08:04 -0700 Subject: media: Update ImageReader to remove MaxImagesAcquiredException * acquiring images now throws IllegalStateException instead of MaxImagesAcquiredException Bug: 10691447 Change-Id: I7ce68f990fb96703705b9181012a28633fea0b7a --- media/jni/android_media_ImageReader.cpp | 35 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'media/jni') diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 56ae6b4..e0195c6 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -43,13 +43,16 @@ using namespace android; -static const char* const MaxImagesAcquiredException = - "android/media/ImageReader$MaxImagesAcquiredException"; - enum { IMAGE_READER_MAX_NUM_PLANES = 3, }; +enum { + ACQUIRE_SUCCESS = 0, + ACQUIRE_NO_BUFFERS = 1, + ACQUIRE_MAX_IMAGES = 2, +}; + static struct { jfieldID mNativeContext; jmethodID postEventFromNative; @@ -685,14 +688,14 @@ static void ImageReader_imageRelease(JNIEnv* env, jobject thiz, jobject image) ctx->returnLockedBuffer(buffer); } -static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, +static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image) { ALOGV("%s:", __FUNCTION__); JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz); if (ctx == NULL) { jniThrowRuntimeException(env, "ImageReaderContext is not initialized"); - return false; + return -1; } CpuConsumer* consumer = ctx->getCpuConsumer(); @@ -700,27 +703,22 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, if (buffer == NULL) { ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than" " maxImages buffers"); - jniThrowException(env, MaxImagesAcquiredException, - "Too many outstanding images, close existing images" - " to be able to acquire more."); - return false; + return ACQUIRE_MAX_IMAGES; } status_t res = consumer->lockNextBuffer(buffer); if (res != NO_ERROR) { if (res != BAD_VALUE /*no buffers*/) { if (res == NOT_ENOUGH_DATA) { - jniThrowException(env, MaxImagesAcquiredException, - "Too many outstanding images, close existing images" - " to be able to acquire more."); + return ACQUIRE_MAX_IMAGES; } else { ALOGE("%s Fail to lockNextBuffer with error: %d ", __FUNCTION__, res); - jniThrowExceptionFmt(env, "java/lang/IllegalStateException", + jniThrowExceptionFmt(env, "java/lang/AssertionError", "Unknown error (%d) when we tried to lock buffer.", res); } } - return false; + return ACQUIRE_NO_BUFFERS; } // Check if the left-top corner of the crop rect is origin, we currently assume this point is @@ -730,7 +728,7 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, ALOGE("crop left: %d, top = %d", lt.x, lt.y); jniThrowException(env, "java/lang/UnsupportedOperationException", "crop left top corner need to at origin"); - return false; + return -1; } // Check if the producer buffer configurations match what ImageReader configured. @@ -761,6 +759,7 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, jniThrowExceptionFmt(env, "java/lang/IllegalStateException", "Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d", outputWidth, outputHeight, imageReaderWidth, imageReaderHeight); + return -1; } if (ctx->getBufferFormat() != buffer->format) { @@ -777,14 +776,14 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, buffer->format, ctx->getBufferFormat()); jniThrowException(env, "java/lang/UnsupportedOperationException", msg.string()); - return false; + return -1; } // Set SurfaceImage instance member variables Image_setBuffer(env, image, buffer); env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp, static_cast(buffer->timestamp)); - return true; + return ACQUIRE_SUCCESS; } static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz) @@ -855,7 +854,7 @@ static JNINativeMethod gImageReaderMethods[] = { {"nativeInit", "(Ljava/lang/Object;IIII)V", (void*)ImageReader_init }, {"nativeClose", "()V", (void*)ImageReader_close }, {"nativeReleaseImage", "(Landroid/media/Image;)V", (void*)ImageReader_imageRelease }, - {"nativeImageSetup", "(Landroid/media/Image;)Z", (void*)ImageReader_imageSetup }, + {"nativeImageSetup", "(Landroid/media/Image;)I", (void*)ImageReader_imageSetup }, {"nativeGetSurface", "()Landroid/view/Surface;", (void*)ImageReader_getSurface }, }; -- cgit v1.1 From cfa553369fd8ef68db751fe1052cd17fd5763965 Mon Sep 17 00:00:00 2001 From: Zhijun He Date: Mon, 16 Sep 2013 09:49:28 -0700 Subject: ImageReader: get correct crop size Bug: 10752797 Change-Id: I2e56d69cde7f5ca669a366646b876861b277a239 --- media/jni/android_media_ImageReader.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'media/jni') diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 94f20bc..16b45be 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -739,11 +739,9 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, int outputHeight = buffer->height; // Correct width/height when crop is set. - if (buffer->crop.getWidth() > 0) { - outputWidth = buffer->crop.getWidth() + 1; - } - if (buffer->crop.getHeight() > 0) { - outputHeight = buffer->crop.getHeight() + 1; + if (buffer->crop.isValid()) { + outputWidth = buffer->crop.getWidth(); + outputHeight = buffer->crop.getHeight(); } int imageReaderWidth = ctx->getBufferWidth(); -- cgit v1.1 From 9e6d073a999d7934aa3f22a5877c6e8e2ce15766 Mon Sep 17 00:00:00 2001 From: Zhijun He Date: Mon, 16 Sep 2013 16:03:36 -0700 Subject: ImageReader: fix the 0 crop rect size issue Rect isValid actually include the zero size case, which we don't want to include in our case. This causes camera ImageReader test case fails at buffer size sanity check. Bug: 9802344 Change-Id: I561f5a049c6117c613df1e1b2789c43af9a19628 --- media/jni/android_media_ImageReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media/jni') diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index fb0f69b..a03dbf3 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -737,7 +737,7 @@ static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, int outputHeight = buffer->height; // Correct width/height when crop is set. - if (buffer->crop.isValid()) { + if (!buffer->crop.isEmpty()) { outputWidth = buffer->crop.getWidth(); outputHeight = buffer->crop.getHeight(); } -- cgit v1.1 From 4eda9f5359347c11914e47f477535c9533674d32 Mon Sep 17 00:00:00 2001 From: Zhijun He Date: Wed, 18 Sep 2013 08:00:02 -0700 Subject: ImageReader: disable NV21 support Bug: 10787131 Change-Id: I5ff0a67144b5ec49eabde6129423a41c9597c2b8 --- media/jni/android_media_ImageReader.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'media/jni') diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index a03dbf3..0030dbd 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -721,13 +721,18 @@ static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, return ACQUIRE_NO_BUFFERS; } + if (buffer->format == HAL_PIXEL_FORMAT_YCrCb_420_SP) { + jniThrowException(env, "java/lang/UnsupportedOperationException", + "NV21 format is not supported by ImageReader"); + return -1; + } + // Check if the left-top corner of the crop rect is origin, we currently assume this point is // zero, will revist this once this assumption turns out problematic. Point lt = buffer->crop.leftTop(); if (lt.x != 0 || lt.y != 0) { - ALOGE("crop left: %d, top = %d", lt.x, lt.y); - jniThrowException(env, "java/lang/UnsupportedOperationException", - "crop left top corner need to at origin"); + jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException", + "crop left top corner [%d, %d] need to be at origin", lt.x, lt.y); return -1; } -- cgit v1.1 From badca26cb218852d32862dada36ee52fce865ad2 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Fri, 20 Sep 2013 10:48:55 -0700 Subject: Add audio level monitoring capabilities in Visualizer effect Extend the visualizer audio effect with the capability to query peak and RMS values for the currently playing audio. Values are expressed in mB and are retrieved as an array of int values in the native layer, and written directly as object fields for the JNI. Bug 8413913 Change-Id: I808075a18e61f85c566544a2bdaae10e5c4a644b --- media/jni/audioeffect/android_media_Visualizer.cpp | 72 ++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'media/jni') diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp index 4d77cfd..40cd06b 100644 --- a/media/jni/audioeffect/android_media_Visualizer.cpp +++ b/media/jni/audioeffect/android_media_Visualizer.cpp @@ -43,6 +43,8 @@ using namespace android; // ---------------------------------------------------------------------------- static const char* const kClassPathName = "android/media/audiofx/Visualizer"; +static const char* const kClassPeakRmsPathName = + "android/media/audiofx/Visualizer$MeasurementPeakRms"; struct fields_t { // these fields provide access from C++ to the... @@ -50,6 +52,8 @@ struct fields_t { jmethodID midPostNativeEvent; // event post callback method jfieldID fidNativeVisualizer; // stores in Java the native Visualizer object jfieldID fidJniData; // stores in Java additional resources used by the native Visualizer + jfieldID fidPeak; // to access Visualizer.MeasurementPeakRms.mPeak + jfieldID fidRms; // to access Visualizer.MeasurementPeakRms.mRms }; static fields_t fields; @@ -257,6 +261,14 @@ android_media_visualizer_native_init(JNIEnv *env) fields.clazzEffect = (jclass)env->NewGlobalRef(clazz); + // Get the Visualizer.MeasurementPeakRms class + clazz = env->FindClass(kClassPeakRmsPathName); + if (clazz == NULL) { + ALOGE("Can't find %s", kClassPeakRmsPathName); + return; + } + jclass clazzMeasurementPeakRms = (jclass)env->NewGlobalRef(clazz); + // Get the postEvent method fields.midPostNativeEvent = env->GetStaticMethodID( fields.clazzEffect, @@ -283,7 +295,24 @@ android_media_visualizer_native_init(JNIEnv *env) ALOGE("Can't find Visualizer.%s", "mJniData"); return; } + // fidPeak + fields.fidPeak = env->GetFieldID( + clazzMeasurementPeakRms, + "mPeak", "I"); + if (fields.fidPeak == NULL) { + ALOGE("Can't find Visualizer.MeasurementPeakRms.%s", "mPeak"); + return; + } + // fidRms + fields.fidRms = env->GetFieldID( + clazzMeasurementPeakRms, + "mRms", "I"); + if (fields.fidRms == NULL) { + ALOGE("Can't find Visualizer.MeasurementPeakRms.%s", "mPeak"); + return; + } + env->DeleteGlobalRef(clazzMeasurementPeakRms); } static void android_media_visualizer_effect_callback(int32_t event, @@ -513,6 +542,26 @@ android_media_visualizer_native_getScalingMode(JNIEnv *env, jobject thiz) } static jint +android_media_visualizer_native_setMeasurementMode(JNIEnv *env, jobject thiz, jint mode) +{ + Visualizer* lpVisualizer = getVisualizer(env, thiz); + if (lpVisualizer == NULL) { + return VISUALIZER_ERROR_NO_INIT; + } + return translateError(lpVisualizer->setMeasurementMode(mode)); +} + +static jint +android_media_visualizer_native_getMeasurementMode(JNIEnv *env, jobject thiz) +{ + Visualizer* lpVisualizer = getVisualizer(env, thiz); + if (lpVisualizer == NULL) { + return MEASUREMENT_MODE_NONE; + } + return lpVisualizer->getMeasurementMode(); +} + +static jint android_media_visualizer_native_getSamplingRate(JNIEnv *env, jobject thiz) { Visualizer* lpVisualizer = getVisualizer(env, thiz); @@ -560,6 +609,25 @@ android_media_visualizer_native_getFft(JNIEnv *env, jobject thiz, jbyteArray jFf } static jint +android_media_visualizer_native_getPeakRms(JNIEnv *env, jobject thiz, jobject jPeakRmsObj) +{ + Visualizer* lpVisualizer = getVisualizer(env, thiz); + if (lpVisualizer == NULL) { + return VISUALIZER_ERROR_NO_INIT; + } + int32_t measurements[2]; + jint status = translateError( + lpVisualizer->getIntMeasurements(MEASUREMENT_MODE_PEAK_RMS, + 2, measurements)); + if (status == VISUALIZER_SUCCESS) { + // measurement worked, write the values to the java object + env->SetIntField(jPeakRmsObj, fields.fidPeak, measurements[MEASUREMENT_IDX_PEAK]); + env->SetIntField(jPeakRmsObj, fields.fidRms, measurements[MEASUREMENT_IDX_RMS]); + } + return status; +} + +static jint android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean jWaveform, jboolean jFft) { Visualizer* lpVisualizer = getVisualizer(env, thiz); @@ -606,9 +674,13 @@ static JNINativeMethod gMethods[] = { {"native_getCaptureSize", "()I", (void *)android_media_visualizer_native_getCaptureSize}, {"native_setScalingMode", "(I)I", (void *)android_media_visualizer_native_setScalingMode}, {"native_getScalingMode", "()I", (void *)android_media_visualizer_native_getScalingMode}, + {"native_setMeasurementMode","(I)I", (void *)android_media_visualizer_native_setMeasurementMode}, + {"native_getMeasurementMode","()I", (void *)android_media_visualizer_native_getMeasurementMode}, {"native_getSamplingRate", "()I", (void *)android_media_visualizer_native_getSamplingRate}, {"native_getWaveForm", "([B)I", (void *)android_media_visualizer_native_getWaveForm}, {"native_getFft", "([B)I", (void *)android_media_visualizer_native_getFft}, + {"native_getPeakRms", "(Landroid/media/audiofx/Visualizer$MeasurementPeakRms;)I", + (void *)android_media_visualizer_native_getPeakRms}, {"native_setPeriodicCapture","(IZZ)I",(void *)android_media_setPeriodicCapture}, }; -- cgit v1.1 From fd2e50086c4f4e2bb064c76a1de73e10c172f387 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Wed, 25 Sep 2013 13:45:41 -0700 Subject: Fix hang b/10855561 Change-Id: I29b046b835ce0ca3644e5c2e8f9bca5c0b380d4b --- media/jni/android_media_MediaCodec.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'media/jni') diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index a859506..b8d437c 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -122,7 +122,7 @@ status_t JMediaCodec::configure( int flags) { sp client; if (bufferProducer != NULL) { - mSurfaceTextureClient = new Surface(bufferProducer); + mSurfaceTextureClient = new Surface(bufferProducer, true /* controlledByApp */); } else { mSurfaceTextureClient.clear(); } -- cgit v1.1