From: Matthieu Bouron <matthieu.bou...@stupeflix.com> --- libavutil/jni.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++ libavutil/jni.h | 29 +++++++++++++ libavutil/jni_internal.c | 36 ++++++++++++++-- libavutil/jni_internal.h | 11 +++++ 4 files changed, 182 insertions(+), 3 deletions(-)
diff --git a/libavutil/jni.c b/libavutil/jni.c index fb89426..296e27b 100644 --- a/libavutil/jni.c +++ b/libavutil/jni.c @@ -20,6 +20,7 @@ #include "config.h" #include "jni.h" +#include "jni_internal.h" #include "log.h" #include <jni.h> @@ -30,6 +31,11 @@ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; JavaVM *java_vm = NULL; +jobject application_context = NULL; + +jobject application_class_loader = NULL; +jmethodID find_class_id = NULL; + void av_jni_register_java_vm(JavaVM *vm) { pthread_mutex_lock(&lock); @@ -53,3 +59,106 @@ JavaVM *av_jni_get_java_vm(void) return vm; } + +#ifdef __ANDROID__ +int av_jni_register_application_context(JNIEnv *env, jobject context) +{ + int ret = 0; + + jclass application_context_class; + jmethodID get_class_loader_id; + + jclass application_class_loader_class; + + pthread_mutex_lock(&lock); + + if (application_context && application_class_loader) { + pthread_mutex_unlock(&lock); + + av_log(NULL, AV_LOG_INFO, "The application context has already been registered\n"); + return ret; + } + + application_context_class = (*env)->GetObjectClass(env, context); + if ((ret = avpriv_jni_exception_check(env, 1, NULL)) < 0) { + goto done; + } + + get_class_loader_id = (*env)->GetMethodID(env, application_context_class, "getClassLoader", "()Ljava/lang/ClassLoader;"); + if ((ret = avpriv_jni_exception_check(env, 1, NULL)) < 0) { + goto done; + } + + application_context = (*env)->NewGlobalRef(env, context); + application_class_loader = (*env)->CallObjectMethod(env, application_context, get_class_loader_id); + if ((ret = avpriv_jni_exception_check(env, 1, NULL)) < 0) { + goto done; + } + + application_class_loader = (*env)->NewGlobalRef(env, application_class_loader); + if ((ret = avpriv_jni_exception_check(env, 1, NULL)) < 0) { + goto done; + } + + application_class_loader_class = (*env)->GetObjectClass(env, application_class_loader); + if ((ret = avpriv_jni_exception_check(env, 1, NULL)) < 0) { + goto done; + } + + find_class_id = (*env)->GetMethodID(env, application_class_loader_class, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;"); + if ((ret = avpriv_jni_exception_check(env, 1, NULL)) < 0) { + goto done; + } + +done: + if (application_context_class) { + (*env)->DeleteLocalRef(env, application_context_class); + } + + if (application_class_loader_class) { + (*env)->DeleteLocalRef(env, application_class_loader_class); + } + + if (ret != 0) { + + if (application_context) { + (*env)->DeleteGlobalRef(env, application_context); + application_context = NULL; + } + + if (application_class_loader) { + (*env)->DeleteGlobalRef(env, application_class_loader); + application_context = NULL; + } + } + + pthread_mutex_unlock(&lock); + + return ret; +} + +jobject av_jni_get_application_context(void) +{ + return application_context; +} + +int av_jni_unregister_application_context(JNIEnv *env) +{ + pthread_mutex_lock(&lock); + + if (application_context) { + (*env)->DeleteGlobalRef(env, application_context); + application_context = NULL; + } + + if (application_class_loader) { + (*env)->DeleteGlobalRef(env, application_class_loader); + application_class_loader = NULL; + } + + pthread_mutex_unlock(&lock); + + return 0; +} + +#endif diff --git a/libavutil/jni.h b/libavutil/jni.h index a6c5c16..320a887 100644 --- a/libavutil/jni.h +++ b/libavutil/jni.h @@ -39,4 +39,33 @@ void av_jni_register_java_vm(JavaVM *vm); */ JavaVM *av_jni_get_java_vm(void); +#ifdef __ANDROID__ +/* + * Register an Android application context that will be used later on + * to load application classes. + * + * @param env JNI environment + * @param context application context + * @return 0 on success, a negative number otherwise + */ +int av_jni_register_application_context(JNIEnv *env, jobject context); + +/* + * Get the registered android application context. + * + * @return the registered android application context + */ +jobject av_jni_get_application_context(void); + +/* + * Unregister the previously registered Android application context + * and delete the global reference associated with it. + * + * @param env JNI environment + * @return 0 on success, a negative number otherwise + * + */ +int av_jni_unregister_application_context(JNIEnv *env); +#endif + #endif /* AVUTIL_JNI_H */ diff --git a/libavutil/jni_internal.c b/libavutil/jni_internal.c index f095469..5e2f7c3 100644 --- a/libavutil/jni_internal.c +++ b/libavutil/jni_internal.c @@ -29,6 +29,11 @@ extern JavaVM *java_vm; +extern jobject application_context; + +extern jobject application_class_loader; +extern jmethodID find_class_id; + JNIEnv *avpriv_jni_attach_env(int *attached, void *log_ctx) { int ret = 0; @@ -243,7 +248,7 @@ int avpriv_jni_exception_check(JNIEnv *env, int log, void *log_ctx) if (!log) { (*(env))->ExceptionClear((env)); - return -1; + return AVERROR_EXTERNAL; } exception = (*env)->ExceptionOccurred(env); @@ -259,7 +264,7 @@ int avpriv_jni_exception_check(JNIEnv *env, int log, void *log_ctx) av_log(log_ctx, AV_LOG_ERROR, "%s\n", message); av_free(message); - return -1; + return AVERROR_EXTERNAL; } int avpriv_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx) @@ -277,7 +282,7 @@ int avpriv_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField last_clazz = NULL; clazz = (*env)->FindClass(env, jfields_mapping[i].name); - if ((ret = avpriv_jni_exception_check(env, mandatory, log_ctx) && mandatory) < 0) { + if ((ret = avpriv_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) { goto done; } @@ -389,3 +394,28 @@ int avpriv_jni_reset_jfields(JNIEnv *env, void *jfields, const struct FFJniField return 0; } + +jclass avpriv_jni_find_application_class(JNIEnv *env, const char *name, void *log_ctx) +{ + jobject ret; + jobject tmp; + + if (!application_class_loader || !find_class_id) { + av_log(log_ctx, AV_LOG_ERROR, "No application class loader has been registered\n"); + return NULL; + } + + tmp = avpriv_jni_utf_chars_to_jstring(env, name, log_ctx); + if (!tmp) { + return NULL; + } + + ret = (*env)->CallObjectMethod(env, application_class_loader, find_class_id, tmp); + if (avpriv_jni_exception_check(env, 1, log_ctx) < 0) { + ret = NULL; + } + + (*env)->DeleteLocalRef(env, tmp); + + return ret; +} diff --git a/libavutil/jni_internal.h b/libavutil/jni_internal.h index 6e66cc2..4d86f02 100644 --- a/libavutil/jni_internal.h +++ b/libavutil/jni_internal.h @@ -144,4 +144,15 @@ int avpriv_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField */ int avpriv_jni_reset_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx); +/* + * Find an application class using the registered Android application context. + * + * @param env JNI environment + * @param name class name (for example: java/lang/String) + * @param log_ctx context used for logging, can be NULL + * @return a local reference to a class object corresponding the provided + * name, or NULL if the class cannot be found + */ +jclass avpriv_jni_find_application_class(JNIEnv *env, const char *name, void *log_ctx); + #endif /* AVUTIL_JNI_INTERNAL_H */ -- 2.7.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel