[FFmpeg-devel] [PATCH 2/5] lavu/jni: add helpers to manage Android application context

Matthieu Bouron matthieu.bouron at gmail.com
Mon Feb 15 18:52:27 CET 2016


From: Matthieu Bouron <matthieu.bouron at 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



More information about the ffmpeg-devel mailing list